bzoj4568幸运数字

倍增加线性基。

线性基开3维,p[i][j]表示从i出发,向上2^i个数的线性基。

查询时类似lca,对这之间的线性基进行合并,得到新的线性基数组a,最后贪心的答案。

倍增的时候对前2i-1个和后2i-1的线性基合并,写的有点复杂...

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 using namespace std;
 5 typedef long long ll;
 6 struct edge {
 7     int v,next;
 8 }e[40005];
 9 ll p[20001][16][61],a[125],val[20005];
10 int head[20005],fa[20005][16],dep[20005];
11 int n,m,x,y,k;
12 void adde(int u,int v) {
13     e[k].v=v;e[k].next=head[u];head[u]=k++;
14 }
15 void addp(int u,int i) {
16     int cnt=0;
17     if (i) for (int j=0;j<=60;j++) {
18         if (p[u][i-1][j]) a[++cnt]=p[u][i-1][j];
19         if (p[fa[u][i-1]][i-1][j]) a[++cnt]=p[fa[u][i-1]][i-1][j];
20     }
21     else a[++cnt]=val[u];
22     for (int k=1;k<=cnt;k++) {
23         for (int j=60;j>=0;j--) 
24             if (a[k]>>j&1)
25                 if (!p[u][i][j]) {p[u][i][j]=a[k];break;}
26                 else a[k]^=p[u][i][j];
27     }
28  
29 }
30 void add(int u,int i) {
31     for (int j=60;j>=0;j--) {
32         ll v=p[u][i][j];
33         if (!v) continue;
34         for (int k=60;k>=0;k--)
35             if (v>>k&1)
36                 if (!a[k]) {a[k]=v;break;}
37                 else v^=a[k];
38     }
39 }
40  
41 void dfs(int u,int f) {
42     fa[u][0]=f;dep[u]=dep[f]+1;
43     for (int i=1;i<=15;i++) fa[u][i]=fa[fa[u][i-1]][i-1];
44     for (int i=0;i<=15;i++) addp(u,i);
45     for (int i=head[u];~i;i=e[i].next) {
46         int v=e[i].v;
47         if (v==f) continue;
48         dfs(v,u);
49     }
50 }
51  
52 ll query(int u,int v) {
53     if (dep[u]<dep[v]) swap(u,v);
54     memset(a,0,sizeof(a));
55     for (int i=15;i>=0;i--) if (dep[fa[u][i]]>=dep[v]) add(u,i),u=fa[u][i];
56     if (u^v) {
57         for (int i=15;i>=0;i--) {
58             if (fa[u][i]==fa[v][i]) continue;
59             add(u,i);add(v,i);u=fa[u][i];v=fa[v][i];
60         }
61         add(u,1);add(v,0);
62     }
63     ll ans=0;add(u,0);
64     for (int i=60;i>=0;i--)
65         ans=max(ans,ans^a[i]);
66     return ans;
67 }
68  
69 int main()
70 {
71     memset(head,-1,sizeof(head));
72     scanf("%d%d",&n,&m);
73     for (int i=1;i<=n;i++) scanf("%lld",&val[i]);
74     for (int i=1;i<n;i++) {
75         scanf("%d%d",&x,&y);
76         adde(x,y);adde(y,x);
77     }
78     dfs(1,0);
79     for (int i=1;i<=m;i++) {
80         scanf("%d%d",&x,&y);
81         printf("%lld\n",query(x,y));
82     }
83     return 0;
84 }

 

posted @ 2016-12-19 21:42  yanglang  阅读(194)  评论(0编辑  收藏  举报