数据结构(trie,启发式合并):HDU 5841 Alice and Bob

 

  这个对数字建二进制trie,然后启发式合并,最重要的是Push_up()操作和Merge()操作,解决了复杂度的问题。
 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 using namespace std;
 5 const int N=100010,M=2000010;
 6 int cnt,fir[N],to[N*2],nxt[N*2];
 7 void addedge(int a,int b){
 8     nxt[++cnt]=fir[a];
 9     to[fir[a]=cnt]=b;
10 }
11 int T,n,Q,cas,tot,dp[N],rt[N];
12 int ch[M][2],sum[M],p[M],w[M],val[M];
13 
14 int Query(int x,int k,int d){
15     if(d==-1)return val[x];int c=(k>>d)&1;
16     if(ch[x][c])return Query(ch[x][c],k,d-1);
17     else return Query(ch[x][c^1],k,d-1);
18 }
19 
20 void Push_up(int x,int d){
21     int l=ch[x][0],r=ch[x][1];
22     sum[x]=sum[l]+sum[r];
23     if(!sum[l]||!sum[r])
24         p[x]=sum[l]?p[l]:p[r];
25     else if(sum[l]>1&&sum[r]>1)
26         p[x]=p[l]>p[r]?p[l]:p[r];
27     else if(sum[l]==1&&sum[r]==1)
28         p[x]=p[l]^p[r];
29     else{
30         if(sum[l]!=1)swap(l,r);
31         p[x]=p[l]^Query(r,p[l],d-1);
32     }
33 }
34 
35 void Insert(int &x,int k,int d){
36     if(!x)x=++tot;
37     if(d==-1){
38         if(sum[x])p[x]=0;
39         else p[x]=val[x]=k;
40         sum[x]+=1;return;
41     }
42     if((k>>d)&1)Insert(ch[x][1],k,d-1);
43     else Insert(ch[x][0],k,d-1);
44     Push_up(x,d);
45 }
46 
47 int Merge(int x,int y,int d){
48     if(!x||!y)return x|y;
49     if(d==-1){
50         sum[x]+=sum[y];
51         if(sum[x]>1)p[x]=0;
52         else p[x]=val[x];
53         return x;
54     }
55     ch[x][0]=Merge(ch[x][0],ch[y][0],d-1);
56     ch[x][1]=Merge(ch[x][1],ch[y][1],d-1);
57     Push_up(x,d);return x;
58 }
59 
60 void DFS(int x,int fa){
61     Insert(rt[x],w[x],16);
62     for(int i=fir[x];i;i=nxt[i])
63         if(to[i]!=fa){DFS(to[i],x);
64             rt[x]=Merge(rt[x],rt[to[i]],16);
65         }
66     if(sum[rt[x]]>=2)dp[x]=p[rt[x]];
67 }
68 
69 void Initialization(){
70     memset(fir,0,sizeof(fir));
71     memset(sum,0,sizeof(sum));
72     memset(dp,-1,sizeof(dp));
73     memset(rt,0,sizeof(rt));
74     memset(ch,0,sizeof(ch));
75     cnt=tot=0;
76 }
77 int main(){
78     scanf("%d",&T);
79     while(T--){
80         scanf("%d",&n);
81         Initialization();
82         for(int i=1;i<=n;i++)
83             scanf("%d",&w[i]);
84         for(int i=1,a,b;i<n;i++){
85             scanf("%d%d",&a,&b);
86             addedge(a,b);addedge(b,a);
87         }
88         DFS(1,0);
89         scanf("%d",&Q);
90         printf("Case #%d:\n",++cas);
91         while(Q--){
92             int x;scanf("%d",&x);
93             printf("%d\n",dp[x]);
94         }
95     }
96     return 0;
97 }

 

转载于:https://www.cnblogs.com/TenderRun/p/5787460.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值