[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 }
View Code

 

posted @ 2021-01-20 15:21  PYWBKTDA  阅读(95)  评论(0编辑  收藏  举报