[luogu6702]Path
维护每一个点到根路径的异或和(记作$d_{k}$),根据异或自反性,$(x,y)$的异或和即$d_{x}\oplus d_{y}$
考虑两条路径的lca,选择其中深度较大的点,另一条路径必然在其子树外,枚举这个点,分别统计子树内外异或和最大的路径
对于子树内,用启发式合并trie树,在合并时顺便统计出答案(枚举较小的一棵trie树中的点,在另一颗trie树中查询),时间复杂度为$o(n\log_{2}n\log_{2}w)$
对于子树外,任选一条全局异或和最大的路径$(p,q)$,然后将其以$p$为根建树(子树内也需要以$p$为根考虑)
将所有点分为两类:1.子树内不含有$q$;2.子树内含有$q$,对于前者必然选择$(p,q)$这条路径,否则也就是从$p$递归到$q$为止的时候
此时,暴力合并子树外的节点(即父亲子树外的节点与父亲子树内除自己外的节点),不难发现每一个节点至多合并一次,暴力合并即可做到$o(n\log_{2}w)$
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 30005 4 int E,n,x,y,z,mx,now_mx,ans,head[N],d[N],vis[N],f[N]; 5 struct ji{ 6 int nex,to,len; 7 }edge[N<<1]; 8 struct trie{ 9 int V; 10 vector<int>v,ch[2]; 11 void New(){ 12 ch[0].push_back(-1); 13 ch[1].push_back(-1); 14 V++; 15 } 16 void init(){ 17 V=0; 18 v.clear(),ch[0].clear(),ch[1].clear(); 19 New(); 20 } 21 void add(int x){ 22 v.push_back(x); 23 int k=0; 24 for(int i=29;i>=0;i--){ 25 int p=((x&(1<<i))>0); 26 if (ch[p][k]<0){ 27 ch[p][k]=V; 28 New(); 29 assert(ch[p][k]>=0); 30 } 31 k=ch[p][k]; 32 } 33 } 34 int query(int x){ 35 if (!v.size())return 0; 36 int k=0,ans=0; 37 for(int i=29;i>=0;i--){ 38 int p=((x&(1<<i))==0); 39 if (ch[p][k]<0)p^=1; 40 else ans+=(1<<i); 41 k=ch[p][k]; 42 } 43 return ans; 44 } 45 int merge(int x){ 46 add(x); 47 return query(x); 48 } 49 }T[N]; 50 int find(int k){ 51 if (k==f[k])return k; 52 return f[k]=find(f[k]); 53 } 54 int merge(int x,int y){ 55 x=find(x),y=find(y); 56 assert(x!=y); 57 if (T[x].v.size()<T[y].v.size())swap(x,y); 58 f[y]=x; 59 int ans=0; 60 for(int i=0;i<T[y].v.size();i++)ans=max(ans,T[x].merge(T[y].v[i])); 61 T[y].init(); 62 return ans; 63 } 64 void add(int x,int y,int z){ 65 edge[E].nex=head[x]; 66 edge[E].to=y; 67 edge[E].len=z; 68 head[x]=E++; 69 } 70 void dfs(int k,int fa,int s){ 71 d[k]=s; 72 f[k]=fa; 73 for(int i=head[k];i!=-1;i=edge[i].nex) 74 if (edge[i].to!=fa)dfs(edge[i].to,k,s^edge[i].len); 75 } 76 void tot(int k,int fa){ 77 now_mx=max(now_mx,T[0].merge(d[k])); 78 for(int i=head[k];i!=-1;i=edge[i].nex) 79 if (edge[i].to!=fa)tot(edge[i].to,k); 80 } 81 void calc(int k,int fa){ 82 int si=T[k].merge(d[k]),so=mx; 83 if (vis[k]){ 84 so=now_mx; 85 now_mx=max(now_mx,T[0].merge(d[k])); 86 for(int i=head[k];i!=-1;i=edge[i].nex) 87 if (!vis[edge[i].to])tot(edge[i].to,k); 88 } 89 for(int i=head[k];i!=-1;i=edge[i].nex) 90 if (edge[i].to!=fa){ 91 calc(edge[i].to,k); 92 si=max(si,merge(k,edge[i].to)); 93 } 94 if (fa)ans=max(ans,si+so); 95 } 96 int main(){ 97 scanf("%d",&n); 98 memset(head,-1,sizeof(head)); 99 for(int i=1;i<n;i++){ 100 scanf("%d%d%d",&x,&y,&z); 101 add(x,y,z); 102 add(y,x,z); 103 } 104 dfs(1,0,0); 105 T[0].init(); 106 for(int i=1;i<=n;i++)mx=max(mx,T[0].merge(d[i])); 107 for(int i=1;i<=n;i++) 108 if (T[0].query(d[i])==mx){ 109 x=i; 110 break; 111 } 112 for(int i=1;i<=n;i++) 113 if ((d[x]^d[i])==mx){ 114 y=i; 115 break; 116 } 117 dfs(x,0,0); 118 while (y){ 119 vis[y]=1; 120 y=f[y]; 121 } 122 for(int i=0;i<=n;i++)T[i].init(); 123 for(int i=1;i<=n;i++)f[i]=i; 124 calc(x,0); 125 printf("%d",ans); 126 }