1. 程式人生 > >hdu 4605 Magic Ball Game(主席樹學習第二彈)

hdu 4605 Magic Ball Game(主席樹學習第二彈)

題目連結:

題目大意:

給出一棵二叉樹,每個點具有權值,給出q次查詢,每次查詢給出一個X,找到到達點v的概率(表示為7x/2y),行走規則為,若X>w[u],那麼走到左孩子和右孩子的概率分別是1/2,X

題目分析:

  • 因為沒有強制線上,所以樹狀陣列也是可以做的,大致思路如下:
    • 首先我們要對所有出現的數進行離散化,因為包括查詢在內數的個數不會超過105
    • 然後對數建立兩個樹狀陣列,記錄數從根到當前點額路徑上的數出現的次數(兩個分別代表向左走時的次數,和向右走時的次數)。
    • 然後進行dfs,在回溯的過程刪掉之前的操作,保證樹狀陣列維護的量是當前點到根的這條路徑上的。
    • 然後對於每個詢問,就是在到達這個點時,因為到它的路徑已經處理過,所以我們知道了從根到這個點的向右走的總次數,從根到這個點的向左走的總數。
    • 那麼按照題目中的表示方法,x = right_less(7的指數);
    • y = 3* ( right_less , left_less ) + right_larger + left_larger;
    • (因為原數的乘法對應到指數上就是加法)
  • 那麼既然是主席樹的練習,當然就算為了練習,也是要來一發主席樹的。
    • 做法相對於離線做法更加簡單,且相似。
    • 首先就是對數進行離散化,但是隻需要對點權進行離散化
    • 然後對每個點建一棵線段樹(採用主席樹的方式,能夠優化空間複雜度到O(2nlogn)
    • 查詢每個點的時候,每棵線段樹維護的資料同上,計算方法也同上。
  • 兩種方法的時間複雜度相同,空間複雜度第二個略大,但是實現上主席樹更加簡潔。

AC程式碼:

樹狀陣列實現:

#pragma comment(linker, "/STACK:1024000000,1024000000")  
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
#define MAX 100007

using namespace std;

int t,n,m,q;
int w[MAX];
vector<int> e[MAX];
int ans[MAX][2];
int
lef[MAX<<1]; int rig[MAX<<1]; int num[MAX],cnum; void addEdge ( int u , int v ) { e[u].push_back ( v ); } struct Query { int id,x,v; }temp; vector<Query> a[MAX]; int lowbit ( int x ) { return x&-x; } void Clear ( ) { for ( int i = 0 ; i < MAX ; i++ ) { e[i].clear(); a[i].clear(); } memset ( lef , 0 , sizeof ( lef ) ); memset ( rig , 0 , sizeof ( rig ) ); cnum = 1; } void add ( int c[] , int x , int v ) { while ( x < cnum ) { c[x] += v; x += lowbit ( x ); } } int sum ( int c[] , int x ) { int ret = 0; while ( x ) { ret += c[x]; x -= lowbit ( x ); } return ret; } int bsearch ( int x ) { int l=1,r=cnum,mid; while ( l != r ) { mid = l+r>>1; if ( num[mid] == x ) return mid; if ( num[mid] < x ) l = mid+1; else r= mid; } return mid; } void dfs ( int u ) { for ( int i = 0 ; i < a[u].size(); i++ ) { int id = a[u][i].id; int x = bsearch ( a[u][i].x ); if ( sum ( lef , x )- sum ( lef , x-1 ) + sum(rig , x ) - sum ( rig , x-1 ) > 0 ) { ans[id][0] = -1; continue; } int ll = sum ( lef , x-1 ); int lr = sum ( lef , cnum-1 ) - sum ( lef , x ); int rl = sum ( rig , x-1 ); int rr = sum ( rig , cnum-1 ) - sum ( rig , x ); ans[id][0] = rl; ans[id][1] = (rl+ll)*3 + rr + lr; } int x = bsearch ( w[u] ); if ( e[u].size() == 0 ) return; int v = e[u][0]; if ( v != -1 ) { add ( lef , x , 1 ); dfs ( v ); add ( lef , x , -1 ); } v = e[u][1]; if ( v != -1 ) { add ( rig , x , 1 ); dfs ( v ); add ( rig , x , -1 ); } } int main ( ) { scanf ( "%d" , &t ); while ( t-- ) { Clear(); scanf ( "%d" , &n ); for ( int i = 1 ; i <= n ; i++ ) { scanf ( "%d" , &w[i] ); num[cnum++] = w[i]; } scanf ( "%d" , &m ); int u,x,y; for ( int i = 0 ; i < m ; i++ ) { scanf ( "%d%d%d" , &u , &x , &y ); addEdge ( u , x ); addEdge ( u , y ); } scanf ( "%d" , &q ); for ( int i = 0 ; i < q ; i++ ) { scanf ( "%d%d" , &temp.v , &temp.x ); temp.id = i; a[temp.v].push_back ( temp ); num[cnum++] = temp.x; } sort ( num+1 , num+cnum ); cnum = unique ( num+1 , num+cnum )-num; dfs ( 1 ); for ( int i = 0 ; i < q ; i++ ) { if ( ans[i][0] == -1 ) puts ( "0" ); else printf ( "%d %d\n" , ans[i][0] , ans[i][1] ); } } return 0; }

主席樹實現:

#pragma comment(linker, "/STACK:1024000000,1024000000")  
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
#define MAX 100007

using namespace std;

int t,n,m,q;
int w[MAX];
vector<int> e[MAX];
int ans[MAX][2];
int lef[MAX<<1];
int rig[MAX<<1];
int num[MAX],cnum;

void addEdge ( int u , int v )
{
    e[u].push_back ( v );
}


struct Query 
{
    int id,x,v;
}temp;

vector<Query> a[MAX];

int lowbit ( int x )
{
    return x&-x;
}

void Clear ( )
{
    for ( int i = 0 ; i < MAX ; i++ )
    {
        e[i].clear();
        a[i].clear();
    }
    memset ( lef , 0 , sizeof ( lef ) );
    memset ( rig , 0 , sizeof ( rig ) );
    cnum = 1;
}

void add ( int c[] , int x , int v  )
{
    while ( x < cnum )
    {
        c[x] += v;
        x += lowbit ( x );
    }
}

int sum ( int c[] , int x )
{
    int ret = 0;
    while ( x )
    {
        ret += c[x];
        x -= lowbit ( x );
    }
    return ret;
}


int bsearch ( int x )
{
    int l=1,r=cnum,mid;
    while ( l != r )
    {
        mid = l+r>>1;
        if ( num[mid] == x ) return mid;
        if ( num[mid] < x ) l = mid+1;
        else r= mid;
    }
    return mid;
}

void dfs ( int u )
{
    for ( int i = 0 ; i < a[u].size(); i++ )
    {
        int  id = a[u][i].id;
        int x = bsearch ( a[u][i].x );
        if ( sum ( lef , x )- sum ( lef , x-1 ) + sum(rig , x ) - sum ( rig , x-1 ) > 0 )
        {
            ans[id][0] = -1;
            continue;
        }
        int ll = sum ( lef , x-1 );
        int lr = sum ( lef , cnum-1 ) - sum ( lef , x );
        int rl = sum ( rig , x-1 );
        int rr = sum ( rig , cnum-1 ) - sum ( rig , x );
        ans[id][0] = rl;
        ans[id][1] = (rl+ll)*3 + rr + lr;

    }
    int x = bsearch ( w[u] );
    if ( e[u].size() == 0 ) return;
    int v = e[u][0];
    if ( v != -1 )
    {
        add ( lef , x , 1 );
        dfs ( v );
        add ( lef , x , -1 );
    }
    v = e[u][1];
    if ( v != -1 )
    {
        add ( rig , x , 1 );
        dfs ( v );
        add ( rig , x , -1 );
    }
}

int main ( )
{
    scanf ( "%d" , &t );
    while ( t-- )
    {
        Clear();
        scanf ( "%d" , &n );
        for ( int i = 1 ; i <= n ; i++ )
        {
            scanf ( "%d" , &w[i] );
            num[cnum++] = w[i];
        }
        scanf ( "%d" , &m );
        int u,x,y;
        for ( int i = 0 ; i < m ; i++ )
        {
            scanf ( "%d%d%d" , &u , &x , &y );
            addEdge ( u , x );
            addEdge ( u , y );
        }
        scanf ( "%d" , &q );
        for ( int i = 0 ; i < q ; i++ )
        {
            scanf ( "%d%d" , &temp.v , &temp.x );
            temp.id = i;
            a[temp.v].push_back ( temp );
            num[cnum++] = temp.x;
        }
        sort ( num+1 , num+cnum );
        cnum = unique ( num+1 , num+cnum )-num;
        dfs ( 1 );
        for ( int i = 0 ; i < q ; i++ )
        {
            if ( ans[i][0] == -1 ) 
                puts ( "0" );  
            else 
                printf ( "%d %d\n" , ans[i][0] , ans[i][1] );
        }
    }
    return 0;
}

相關推薦

hdu 4605 Magic Ball Game(主席學習第二)

題目連結: 題目大意: 給出一棵二叉樹,每個點具有權值,給出q次查詢,每次查詢給出一個X,找到到達點v的概率(表示為7x/2y),行走規則為,若X>w[u],那麼走到左孩子和右孩子的概率分別是1/2,X 題目分析: 因為沒有強制線上,

HDU 4605 Magic Ball Game (線上主席|| 離線 線段)

題意:給出一棵二叉樹,每個結點孩子數目為0或者2。每個節點都有一個權值,初始在根,扔一個篩子,篩子的值與結點的權值大小關係影響往左往右的概率。 問給出篩子權值,問到達某個結點的概率。 做法:肯定需要統計每個點到根的路徑中,有哪些結點是需要往左孩子走,哪些需要往右孩子走。

HDU-4605-Magic Ball Game (離散化+狀陣列+離線)

題目連結 題意:有一顆樹,每個點有一個權值,從根節點放一個求往下落,球的值小於當前節點的值,往左右兒子落的概率各為1/2,相等則會停在這個節點,球的值大於當前節點的值往做兒子落的概率是1/8,往右兒子落的概率是7/8,q此詢問,每個詢問給一個點x和值w,問這個求落到x的概率

HDU 4605 Magic Ball Game(可持續化線段狀陣列,離散化)

When the magic ball game turns up, Kimi immediately falls in it. The interesting game is made up of N balls, each with a weight of w[i]. These N balls for

hdu 4605 Magic Ball Game(可持久化笛卡爾

題目大意 給定一棵二叉樹,保證節點沒有孩子節點或者有兩個孩子節點,並且每個節點有一個權值W[i],1為根節點,樹給定的方式m個關係u a b,表示u節點的左孩子為a,右孩子為b。現在從根節點放一個權值為X的小球: - X = W[u]時:小球停留在該

hdu 4348 To the moon(主席區間操作)

esp ace 標記 return ++i urn div acm str 題目鏈接:hdu 4348 To the moon 題意: 給你n個數,有m個操作。 1.給區間[l,r]的所有數+d,並且時間戳+1 2.詢問當前時間戳的區間和。 3.詢問過去時間戳t的區間和。

hdu 5919--Sequence II(主席--求區間不同數個數+區間第k大)

positions minus -s ima date rst itl 主席樹 技術 題目鏈接 Problem Description Mr. Frog has an integer sequence of length n, which can be denot

HDU 4417 Super Mario(主席

there mon ref seve pin ans ins Go follow Super Mario Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)T

主席學習筆記

using 鏈表 自然 bit namespace \n root getch bool Part I 靜態主席樹 定義 主席樹最基礎可以維護區間K大的問題,由於其本質是可持久化線段樹,所以要對線段樹有很深的理解。 栗子:區間第K小 首先這種處理區間的問題肯定要想到區間數據

hdu 4417 Super Mario (主席

代碼 i++ uil 我們 php amp build iostream sort 鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=4417 題意: 給你段長為n的序列,有q個詢問,每次詢問區間[l.r]內有多少個數小於等於k

主席學習

unique ret update str 前綴 個數 clu net spa 很好的博客:https://blog.csdn.net/qq_39809664/article/details/79934516 可持久化數組 #include<algorithm&

2018黑龍江省賽 A Sequence Game 主席+st表 / 主席+線段 / st表+莫隊+離散化

7218: A Sequence Game 時間限制: 1 Sec  記憶體限制: 128 MB 提交: 128  解決: 32 [提交] [狀態] [討論版] [命題人:admin] 題目描述 One da

K-th Number POJ - 2104 (主席 學習詳解)

https://cn.vjudge.net/problem/POJ-2104 題意 給你N個數 嗎、M次查詢,每次查詢給你 IJK 問第I個數到第J個數中第K大 思路 字典樹,每新增一個數都建立一棵線段樹,J和I 做減法就可以的到這個區間的線段樹 #include <c

HDU 4348 To the moon [主席 區間修改]

題意:給你長度為n的陣列,共有四個操作: 1.對區間【L,R】增加d,並時間增加1    2.詢問當前時間的區間【L,R】的和 3.詢問時間為T時的區間【L,R】的和 4.返回到時間為T的時候 題解:既然有歷史版本,肯定是用主席樹了,但是主席樹的區間的修改,一種辦法是在遇到

[HDU 2665] Kth number (主席入門)

HDU - 2665 靜態區間第 k大 這道題有很多種比主席樹簡單了一萬倍的演算法 不過作為主席樹入門還是很合適的 orz 這題的具體做法就是,先離散化值,在建立權值線段樹 從左到右掃一遍陣列,對第 i個數,在 A[i]的位置 +1 然後

主席學習--入門

      本篇文章,講講主席樹入門,以及區間第K大,或者區間第K小。學習主席樹前提是要學習線段樹,主席樹也就是多棵線段樹,每次更新都需要記錄之前的線段樹,如果每次新建一棵線段樹。比較浪費空間時間。因為每次更新一個點只會修改一條樹鏈。其他的樹節點資訊不改變,所以可以公用一些

HDU 2665 Kth number(主席靜態區間第K大)題解

可持久化 unique algorithm using 主席樹 可持久化線段樹 long spa 靜態區 題意:問你區間第k大是誰 思路:主席樹就是可持久化線段樹,他是由多個歷史版本的權值線段樹(不是普通線段樹)組成的。 具體可以看q學姐的B站視頻 代碼:

Mybatis學習第二

今天主要學習了Mybatis中關係對映檔案的編寫,其中主要包括增刪改查SQL語句的編寫。在通過Mybatis進行介面化程式設計時,我們只需要定義相應的介面以及介面方法,然後編寫與之對應的對映檔案,即可採用介面呼叫的方式輕鬆的進行對資料庫的操作。 對映檔案以 <mapp

HDU 4605 (主席)

題意:有一棵樹二叉,每個節點有一個數字。每次詢問一個節點和一個數字,問這個數字經過這個節點的概率。一個數字從根開始往下走,如果走過的節點數字和他相同,就停在這裡;如果節點數字比他大,向左向右的概率都是1/2;否則向左的概率是1/8,向右的概率是7/8。 對

hdu 5975---Aninteresting game狀數組)

owb form target pla rst phy ace empty creat 題目鏈接 Problem Description Let’s play a game.We add numbers 1,2...n in increasing or