bzoj4568: [Scoi2016]幸运数字(LCA+线性基)

4568: [Scoi2016]幸运数字

题目:传送门


 

题解:

   好题!!!

   之前就看过,当时说是要用线性基...就没学

   填坑填坑:

   %%%线性基 && 神犇

   主要还是对于线性基的运用和LCA的灵活运用吧:

   设f[i][j][65]表示i到2^j-1的线性基集合

   跑LCA,边跑边暴力合并路径上的线性基咯,最后find_max一下xor的最大值就好啦

   槽点:注意^符号的优先级还有空间大小...有点恶心


代码:

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<cstdlib>
  4 #include<cmath>
  5 #include<algorithm>
  6 using namespace std;
  7 typedef long long LL;
  8 struct node
  9 {
 10     int x,y,next;
 11 }a[41000];int len,last[21000];
 12 void ins(int x,int y)
 13 {
 14     len++;a[len].x=x;a[len].y=y;
 15     a[len].next=last[x];last[x]=len;
 16 }
 17 void add(LL *a,LL x)
 18 {
 19     for(int i=60;i>=0;i--)
 20     {
 21         if(x&(1LL<<i))
 22         {
 23             if(!a[i]){a[i]=x;break;}
 24             x^=a[i];
 25         }
 26     }
 27 }
 28 void merge(LL *a,LL *b)
 29 {
 30     for(int i=0;i<=60;i++)
 31         if(b[i])add(a,b[i]);
 32 }
 33 LL ans[65],bin[65],f[21000][21][65],dep[21000],fa[21000][21];
 34 void pre_tree_node(int x)
 35 {
 36     for(int i=1;bin[i]<=dep[x];i++)
 37     {
 38         fa[x][i]=fa[fa[x][i-1]][i-1];
 39         memcpy(f[x][i],f[x][i-1],sizeof(f[x][i]));
 40         merge(f[x][i],f[fa[x][i-1]][i-1]);
 41     }
 42     for(int k=last[x];k;k=a[k].next)
 43     {
 44         int y=a[k].y;
 45         if(y!=fa[x][0])
 46         {
 47             fa[y][0]=x;
 48             dep[y]=dep[x]+1;
 49             pre_tree_node(y);
 50         }
 51     }
 52 }
 53 void solve(int x,int y)
 54 {
 55     if(dep[x]<dep[y])swap(x,y);
 56     for(int i=20;i>=0;i--)
 57         if(dep[fa[x][i]]>=dep[y])
 58             merge(ans,f[x][i]),x=fa[x][i];
 59     if(x==y){merge(ans,f[x][0]);return ;}
 60     for(int i=20;i>=0;i--)
 61         if(bin[i]<=dep[x] && fa[x][i]!=fa[y][i])
 62         {
 63             merge(ans,f[x][i]),merge(ans,f[y][i]);
 64             x=fa[x][i],y=fa[y][i];
 65         }
 66     merge(ans,f[x][0]),merge(ans,f[y][0]);
 67     merge(ans,f[fa[x][0]][0]);
 68     return ;
 69 }
 70 LL find_max()
 71 {
 72     LL sum=0;
 73     for(int i=60;i>=0;i--)
 74         if((sum^ans[i])>sum)
 75             sum^=ans[i];
 76     return sum;
 77 }
 78 int n,T;
 79 int main()
 80 {
 81     scanf("%d%d",&n,&T);
 82     bin[0]=1LL;for(int i=1;i<=60;i++)bin[i]=bin[i-1]<<1;
 83     len=0;memset(last,0,sizeof(last));
 84     for(int i=1;i<=n;i++)
 85     {
 86         LL x;scanf("%lld",&x);
 87         add(f[i][0],x);
 88     }
 89     for(int i=1;i<n;i++)
 90     {
 91         int x,y;scanf("%d%d",&x,&y);
 92         ins(x,y);ins(y,x);
 93     }
 94     fa[1][0]=0;dep[1]=1;pre_tree_node(1);
 95     while(T--)
 96     {
 97         int x,y;scanf("%d%d",&x,&y);
 98         memset(ans,0,sizeof(ans));
 99         solve(x,y);
100         printf("%lld\n",find_max());
101     }
102     return 0;
103 }

 

posted @ 2018-03-10 12:27  CHerish_OI  阅读(229)  评论(0编辑  收藏  举报