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 }