G70 前缀线性基+贪心法+LCA P3292 [SCOI2016] 幸运数字

视频链接:G70 前缀线性基+贪心法+LCA P3292 [SCOI2016] 幸运数字_哔哩哔哩_bilibili

 

 

 

G69 前缀线性基+贪心法 CF1100F Ivan and Burgers - 董晓 - 博客园 (cnblogs.com)

D09 倍增算法 P3379【模板】最近公共祖先(LCA) - 董晓 - 博客园 (cnblogs.com)

P3292 [SCOI2016] 幸运数字 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

// 前缀线性基+贪心法+LCA O(60*60*q)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

#define LL long long
const int N=20005;
int idx,head[N],to[N<<1],ne[N<<1];
void add(int x,int y){
  to[++idx]=y;ne[idx]=head[x];head[x]=idx;
}
int n,q,x,y;
int dep[N],fa[N][16];
int pos[N][61];
LL a[N],b[61],p[N][61];

void insert(int u,int f){
  for(int i=0;i<=60;i++) //复制父版
    p[u][i]=p[f][i],pos[u][i]=pos[f][i];
  LL x=a[u]; int P=u;
  for(int i=60;i>=0;--i){
    if((x>>i)&1){
      if(!p[u][i]){ //不存在则加入
        p[u][i]=x;
        pos[u][i]=P;
        break;
      }
      // 存在则先交换,后异或
      if(dep[pos[u][i]]<dep[P])
        swap(x,p[u][i]),swap(pos[u][i],P);
      x^=p[u][i];
    }
  }
}
void dfs(int u,int f){
  dep[u]=dep[f]+1; fa[u][0]=f;
  for(int i=1;i<=15;i++)
    fa[u][i]=fa[fa[u][i-1]][i-1];
  insert(u,f); //构造线性基
  for(int i=head[u];i;i=ne[i])
    if(to[i]!=f) dfs(to[i],u);
}
int LCA(int x,int y){
  if(dep[x]<dep[y]) swap(x,y);
  for(int i=15;i>=0;--i)
    if(dep[fa[x][i]]>=dep[y]) x=fa[x][i];
  if(x==y) return x;
  for(int i=15;i>=0;--i)
    if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
  return fa[x][0];
}
LL query(int x,int y){
  int lca=LCA(x,y);
  for(int i=60;i>=0;--i)  //提取x~lca链的基
    b[i]=dep[pos[x][i]]>=dep[lca]?p[x][i]:0;
  for(int i=60;i>=0;--i){ //暴力合并基
    if(dep[pos[y][i]]>=dep[lca]){
      LL x=p[y][i];       //提取y~lca链的基
      for(int j=i;j>=0;--j){
        if(x>>j&1){
          if(!b[j]){b[j]=x;break;}
          x^=b[j];
        }
      }
    }
  }
  LL ans=0;
  for(int i=60;i>=0;--i)ans=max(ans,ans^b[i]);
  return ans;  
}
int main(){
  scanf("%d%d",&n,&q);
  for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
  for(int i=2;i<=n;i++){
    scanf("%d%d",&x,&y); add(x,y);add(y,x);
  }
  dfs(1,0); //树增
  while(q--){
    scanf("%d%d",&x,&y);
    printf("%lld\n",query(x,y));
  }
}

 

posted @ 2024-07-21 10:15  董晓  阅读(14)  评论(0编辑  收藏  举报