xsy1122 路径 点分治+trie

Posted xiefengze1

tags:

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

题目大意:给你一棵n个点的树,树边上有边权,对于每一个点,你要求出经过该点的所有的路径中,路径异或和最大的值。

数据范围:$n≤10^5$,边权$≤10^9$。

 

我们考虑枚举每一条路径,显然这个是会T的,于是我们用点分治来实现这个过程。

对于一棵以$x$为根的子树,假设它有$k$个儿子,编号$v1....k$。

我们维护一棵$trie$树,记录所有从根到以$v1,v2.....vp$为跟的子树中的路径长度。

对于从跟到第$p+1$个儿子为跟的树中的每一条路径,我们都丢到$trie$树中查询与最大的异或值。

在查询最大值的过程中,我们维护一个$max_i$,表示从根到i的路径上的最大路径异或和。我们可以通过简单的标记上传去实现更新。

然后再将所有终点在$p+1$个子树中的路径加入到$trie$树种。

 

时间复杂度:$O(n log n log v)$。

  1 #include<bits/stdc++.h>
  2 #define M 100005
  3 #define INF ((1<<31)-1)
  4 using namespace std;
  5 
  6 struct edge{int u,v,next;}e[M*2]={0}; int head[M]={0},Use=0;
  7 void add(int x,int y,int z){Use++;e[Use].u=y;e[Use].v=z;e[Use].next=head[x];head[x]=Use;}
  8 
  9 int use=1;
 10 struct trie{int a[2];}a[M*30]={0};
 11 void add(int x){
 12     int now=1;
 13     for(int i=30;~i;i--){
 14         bool k=(1<<i)&x;
 15         if(a[now].a[k]) now=a[now].a[k];
 16         else a[now].a[k]=++use,a[use].a[0]=a[use].a[1]=0,now=use;
 17     }
 18 }
 19 int query(int x){
 20     int now=1,res=0;
 21     for(int i=30;~i;i--){
 22         bool k=(1<<i)&x;
 23         if(a[now].a[k^1]) now=a[now].a[k^1],res+=(1<<i);
 24         else now=a[now].a[k];
 25     }
 26     return res;
 27 }
 28 
 29 int siz[M]={0},vis[M]={0};
 30 int minn=INF,minid=0;
 31 void dfssiz(int x,int fa){
 32     siz[x]=1;
 33     for(int i=head[x];i;i=e[i].next)
 34     if(e[i].u!=fa&&vis[e[i].u]==0)
 35     dfssiz(e[i].u,x),siz[x]+=siz[e[i].u];
 36 }
 37 void dfsmax(int x,int fa,int fsiz){
 38     int maxn=fsiz-siz[x];
 39     for(int i=head[x];i;i=e[i].next)
 40     if(e[i].u!=fa&&vis[e[i].u]==0){
 41         dfsmax(e[i].u,x,fsiz);
 42         maxn=max(maxn,siz[e[i].u]);
 43     }
 44     if(maxn<minn) minn=maxn,minid=x;
 45 }
 46 int makeroot(int x){
 47     dfssiz(x,0);
 48     minn=INF; minid=0;
 49     dfsmax(x,0,siz[x]);
 50     return minid;
 51 }
 52 
 53 int ans[M]={0},now[M]={0};
 54 void upans(int x,int fa,int Val){
 55     int hh=query(Val);
 56     now[x]=hh;
 57     for(int i=head[x];i;i=e[i].next) 
 58     if(e[i].u!=fa&&vis[e[i].u]==0){
 59         upans(e[i].u,x,Val^e[i].v);
 60         now[x]=max(now[x],now[e[i].u]);
 61     }
 62     ans[x]=max(ans[x],now[x]);
 63 }
 64 void addtrie(int x,int fa,int Val){
 65     add(Val);
 66     for(int i=head[x];i;i=e[i].next)
 67     if(e[i].u!=fa&&vis[e[i].u]==0){
 68         addtrie(e[i].u,x,Val^e[i].v);
 69     }
 70 }
 71 
 72 stack<int> s;
 73 void dfs(int x){
 74     x=makeroot(x); vis[x]=1;
 75     
 76     a[1].a[0]=a[1].a[1]=0; use=1;
 77     add(0);
 78     for(int i=head[x];i;i=e[i].next) if(vis[e[i].u]==0){
 79         upans(e[i].u,x,e[i].v);
 80         ans[x]=max(ans[x],now[e[i].u]);
 81         addtrie(e[i].u,x,e[i].v);
 82         s.push(i);
 83     }
 84     
 85     a[1].a[0]=a[1].a[1]=0; use=1;
 86     add(0);
 87     while(!s.empty()){
 88         int i=s.top(); s.pop();
 89         upans(e[i].u,x,e[i].v);
 90         ans[x]=max(ans[x],now[e[i].u]);
 91         addtrie(e[i].u,x,e[i].v);
 92     }
 93     
 94     for(int i=head[x];i;i=e[i].next) if(vis[e[i].u]==0)
 95     dfs(e[i].u);
 96 }
 97 
 98 int main(){
 99     int n; scanf("%d",&n);
100     for(int i=1;i<n;i++){
101         int x,y,z; scanf("%d%d%d",&x,&y,&z);
102         add(x,y,z); add(y,x,z);
103     }
104     dfs(1);
105     for(int i=1;i<=n;i++) printf("%d
",ans[i]);
106 }

以上是关于xsy1122 路径 点分治+trie的主要内容,如果未能解决你的问题,请参考以下文章

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

XSY2307树的难题

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

Tsinsen A1486. 树(王康宁)

Codeforces 888G Xor-MST - 分治 - 贪心 - Trie

牛客练习赛11 B trie树+拓扑判环 E 分治求平面最近点对