hdu6191(广西邀请赛K)

来源:互联网 发布:mac局域网通信软件 编辑:程序博客网 时间:2024/04/25 08:43

题目链接
题意是给一棵树,每个点有点权,然后每次询问给一个子树和一个x,问子树上面所有的点中异或x的最大值是多少。
这个题目可以离线用字典树合并的方式,从叶子往根去合并,也可以用dfs序直接把子树转化为区间上的问题,然后用可持续化trie树去做。
可持续化trie树本质其实和主席树的建树方式差不多,动态建树且每一次新增一条链。然后当询问某一个子树的时候,通过dfs序把它变成一个区间,然后就是01字典树上面走走。从高到底看看这一位有没有与x相反的bit位,如果有还要判断是否在L到R的区间上。

#include<cmath>#include<algorithm>#include<cstring>#include<string>#include<set>#include<map>#include<time.h>#include<cstdio>#include<vector>#include<list>#include<stack>#include<queue>#include<iostream>#include<stdlib.h>using namespace std;#define  LONG long longconst int   INF=0x3f3f3f3f;const LONG  MOD=1e9+ 7;const double PI=acos(-1.0);#define clrI(x) memset(x,-1,sizeof(x))#define clr0(x) memset(x,0,sizeof x)#define clr1(x) memset(x,INF,sizeof x)#define clr2(x) memset(x,-INF,sizeof x)#define EPS 1e-10#define lson  l , mid , rt<< 1#define rson  mid + 1 ,r , (rt<<1)+1#define root 1, n , 1const int MAXN = 140000 ;int L[MAXN + 50 ] , R[MAXN + 50] ;int TOT = 0;int Root[MAXN + 50 ] ;struct Trie{    int next[2] ;    int sum ;    Init()    {        clrI(next) ;        sum = 0 ;    }}trie[ (MAXN << 6 )+ (MAXN << 5)];struct Edge{    int next ,to ;}edge[200100] ;int head[MAXN] ;int tot = 0 ;int cnt = 0 ;int V[MAXN] ;int Rank[MAXN] ;void Init(){    tot = 0 ;    clrI(head) ;    cnt = 0 ;    TOT = 0;}void Add(int u ,int  v){    edge[++tot].to = v;    edge[tot].next = head[u] ;    head[u] = tot ;}void Dfs(int pre ,int u){    L[u] = ++cnt ;    Rank[cnt] = u ;    for(int i = head[u] ;~i ; i = edge[i].next)    {        int v =edge[i].to ;        if(v == pre ) continue ;        Dfs(u , v) ;    }    R[u] = cnt ;}void Build(int x){    int now = 0 ;    for(int i = 31 ; i >= 0 ; -- i)    {        int p = (( x>>i ) &  1) ;        if(trie[now].next[p] == -1)        {            trie[now].next[p] = ++TOT ;            trie[TOT].Init() ;        }        now = trie[now].next[p] ;        trie[now].sum  ;    }}int Insert(int x , int rt , int d ){    TOT ++ ;    int now = TOT ;    trie[now] = trie[rt] ;    if( d== -1) return now ;    int p = ( (x>>d) & 1 ) ;    trie[now].next[p] = Insert( x , trie[now].next[p],d-1 ) ;    trie[trie[now].next[p]].sum ++ ;    return now ;}int Que(int x ,int  L_rt,int R_rt){    int res = 0 ;    for(int i = 31 ; i >= 0 ; -- i)    {        int p = ((x>>i)&1)  ;        if(trie[R_rt].next[p^1] == -1)        {            R_rt = trie[R_rt] .next[p] ;            L_rt = trie[L_rt] .next[p] ;        }        else        {            int tmp1 = trie[R_rt].next[p^1] ;            int tmp2 = trie[L_rt].next[p^1 ] ;            if(trie[tmp1].sum - trie[tmp2].sum > 0)            {                res += (1<<i) ;                R_rt = tmp1 ;                L_rt = tmp2 ;            }            else            {                R_rt = trie[R_rt].next[p] ;                L_rt = trie[L_rt].next[p] ;            }        }    }    return res ;}int main(){    int n , q ;    while(cin >> n >> q)    {        Init() ;        for(int i = 1; i <= n ; ++ i)        scanf("%d",&V[i]) ;        int tmp  ;        f  or(int i= 1;i < n ; ++i)        {            scanf("%d",&tmp ) ;            Add(i + 1, tmp ) ;            Add(tmp , i + 1 ) ;        }        Dfs( -1 , 1) ;        for(int i=  1;i<= n ; ++ i)        trie[0].Init() ;        for(int i = 1 ;i<= n ; ++ i)            Build(V[Rank[ i ] ]) ;        Root[0] = 0 ;        for(int i = 1;i<= n ; ++ i)            Root[i] = Insert( V[Rank[i]] , Root[i-1 ] , 31) ;        int u , x;        int l ,r ;        int ans = 0 ;        while(q --)        {            scanf("%d%d",&u,&x) ;            l = L[u] - 1;            r = R[u] ;            ans = Que(x , Root[l] , Root[r]) ;            cout<<ans<<endl ;        }        for(int i = 0 ;i<= TOT ;++ i)        {            clrI( trie[i].next ) ;            trie[i].sum = 0 ;        }    }    return 0 ;}
原创粉丝点击