xsy1214 异或路径(xorpath) 点分治+可持久化trie

Posted xiefengze1

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了xsy1214 异或路径(xorpath) 点分治+可持久化trie相关的知识,希望对你有一定的参考价值。

题目大意:给你一棵$n$个点的树,每个点有一个点权$x$,问你所有路径中点权异或和最大的路径的异或和

数据范围:$n≤30000$,$x≤2^{31}-1$。

如果是边上有点权的话非常简单,直接一个$trie$就可以水过去了。

然而这题是点权,非常烦人。我们考虑用点分治去解决。

假设当前需要遍历的树的重心是$x$,我们开一个可持久化$trie$,我们用$son[x][i]$表示$x$的第$i$个儿子(我们假设总共有$p_x$个),将从$son[x][i]$出发的路径异或和加入第$[i,p_x]$个$trie$树中,当我们遍历出一条从$x$出发,经过$son[x][i]$的路径时,我们把这个路径的异或和放入第$i-1$个$trie$树中进行搜索。

我们已知点分治的时间复杂度是$O(n log n)$,由于这里面套了一个可持久化$trie$,那么时间复杂度就是$O(n log n log_2^{max{x}}$。

然后我的$trie$树出了锅,路径长度的最后一个二进制位没有被塞进$trie$中,然后成功$GG$

  1 #include<bits/stdc++.h>
  2 #define M 100005
  3 #define INF 19260817
  4 using namespace std;
  5 
  6 struct edge{int u,next;}e[M*2]={0}; int head[M]={0},Use=0;
  7 void add(int x,int y){Use++;e[Use].u=y;e[Use].next=head[x];head[x]=Use;}
  8 
  9 int num[M]={0},vis[M]={0};
 10 
 11 int siz[M]={0};
 12 
 13 void dfssiz(int x,int fa){
 14     siz[x]=1;
 15     for(int i=head[x];i;i=e[i].next)
 16     if(e[i].u!=fa&&vis[e[i].u]==0){
 17         dfssiz(e[i].u,x);
 18         siz[x]+=siz[e[i].u];
 19     }
 20 }
 21 int minn,minid;
 22 void dfsmax(int x,int fa,int fasiz){
 23     int maxn=fasiz-siz[x];
 24     for(int i=head[x];i;i=e[i].next)
 25     if(e[i].u!=fa&&vis[e[i].u]==0){
 26         dfsmax(e[i].u,x,fasiz);
 27         maxn=max(maxn,siz[e[i].u]);
 28     }
 29     if(maxn<minn) minn=maxn,minid=x;
 30 }
 31 
 32 int makeroot(int x){
 33     dfssiz(x,0);
 34     minn=INF; minid=0;
 35     dfsmax(x,0,siz[x]);
 36     return minid;
 37 }
 38 
 39 struct trie{
 40     int a[2];
 41 }a[M*20]={0};int root[M]={0},use=0;
 42 
 43 void add(int &x,int zhi,int wei){
 44     a[++use]=a[x]; x=use; int hh=0;
 45     if(wei<0) return;
 46     if((1<<wei)&zhi) hh=1;
 47     add(a[x].a[hh],zhi,wei-1);
 48 }
 49 int query(int x,int zhi,int wei){
 50     if(wei<0||x==0) return 0; 
 51     int hh=1,ans=0;
 52     if((1<<wei)&zhi) hh=0;
 53     if(!a[x].a[hh]) return query(a[x].a[hh^1],zhi,wei-1);
 54     else return (1<<wei)+query(a[x].a[hh],zhi,wei-1);
 55 }
 56 
 57 void dfsdis(int x,int fa,int hh,int cnt){
 58     hh^=num[x];
 59     add(root[cnt],hh,30);
 60     for(int i=head[x];i;i=e[i].next)
 61     if(e[i].u!=fa&&vis[e[i].u]==0){
 62         dfsdis(e[i].u,x,hh,cnt);
 63     }
 64 }
 65 
 66 int ans=0;
 67 
 68 void query(int x,int fa,int hh,int cnt){
 69     hh^=num[x];
 70     int now=query(root[cnt-1],hh,30);
 71     ans=max(ans,now);
 72     ans=max(ans,hh);
 73     for(int i=head[x];i;i=e[i].next)
 74     if(e[i].u!=fa&&vis[e[i].u]==0){
 75         query(e[i].u,x,hh,cnt);
 76     }
 77 }
 78 
 79 void calc(int x){
 80     int cnt=0;
 81     for(int i=head[x];i;i=e[i].next)
 82     if(vis[e[i].u]==0){
 83         cnt++; root[cnt]=root[cnt-1];
 84         dfsdis(e[i].u,x,0,cnt);
 85     }
 86     cnt=0;
 87     for(int i=head[x];i;i=e[i].next)
 88     if(vis[e[i].u]==0){
 89         cnt++;
 90         ans=max(ans,num[x]);
 91         query(e[i].u,x,num[x],cnt);
 92     }
 93     use=0; memset(root,0,(cnt+1)<<2);
 94 }
 95 
 96 void dfs(int x){
 97     x=makeroot(x); vis[x]=1; 
 98     calc(x);
 99     for(int i=head[x];i;i=e[i].next)
100     if(vis[e[i].u]==0) dfs(e[i].u);
101 }
102 
103 int main(){
104 //    freopen("in.txt","r",stdin);
105 //    freopen("out.txt","w",stdout);
106     int n; scanf("%d",&n);
107     for(int i=1;i<=n;i++) scanf("%d",num+i);
108     for(int i=1;i<n;i++){
109         int x,y; scanf("%d%d",&x,&y);
110         add(x,y); add(y,x);
111     }
112     dfs(1);
113     cout<<ans<<endl;
114 }

 

以上是关于xsy1214 异或路径(xorpath) 点分治+可持久化trie的主要内容,如果未能解决你的问题,请参考以下文章

《算法竞赛进阶指南》0x16Trie POJ3764异或最大路径

2019 icpc西安邀请赛 点分治

XSY2307树的难题

xsy1230 树(tree) 点分治+线段树

Tsinsen-A1486树(王康宁) 点分治 + Trie

Codeforces 938G 线段树分治 线性基 可撤销并查集