题意:
给出一个有权树,求树上两点路径的最大异或和;
n<=100000;
题解:
考虑异或的性质,如果任选一点为根,处理出所有点的异或深度;
那么将两点的深度异或起来,LCA到根的路径就异或了两次相当于没有;
所以异或距离就是两点异或深度的异或和,问题就转化成了从n个数中选两个数使异或和最大;
这个经典问题就可以把数字按位存进01trie树,从高位到低位贪心求解;
复杂度O(31n);
HINT:
推荐使用unsigned int ;
深搜似乎不爆栈;
字典树开31倍空间,我就是因为这个先RE在MLE的= =;
有点卡vector,(链式前向星别写错) 我就是因为这个TLE改成WA的= =;
代码:
#include<vector> #include<stdio.h> #include<string.h> #include<algorithm> #define N 110000 using namespace std; typedef unsigned int it; it to[N<<1],val[N<<1],p[N<<1],head[N],tot; it dis[N],next[N<<5][2],root,cnt,ans; bool vis[N]; void init() { cnt=1,root=1,ans=0,tot=0; memset(head,0,sizeof(head)); memset(next,0,sizeof(next)); memset(vis,0,sizeof(vis)); } void add(it x,it y,it v) { to[++tot]=y; p[tot]=head[x]; val[tot]=v; head[x]=tot; } void dfs(it x,it pre,it d) { dis[x]=d; it i,y; for(i=head[x];i;i=p[i]) { if((y=to[i])!=pre) dfs(y,x,d^val[i]); } } void Insert(it x) { it t=1<<31,p=root; bool index; while(t) { index=t&x?1:0; if(next[p][index]==0) next[p][index]=++cnt; p=next[p][index]; t>>=1; } } void query(it x) { it t=1<<31,p=root; it ret=0; bool index; while(t) { index=t&x?0:1; if(next[p][index]) p=next[p][index], ret|=t; else p=next[p][!index]; t>>=1; } ans=max(ans,ret); } int main() { it n,m,i,j,k,x,y,v; while(scanf("%d",&n)!=EOF) { init(); for(i=1;i<n;i++) { scanf("%d%d%d",&x,&y,&v); x++,y++; add(x,y,v); add(y,x,v); } dfs(1,0,0); Insert(0); for(i=2;i<=n;i++) { query(dis[i]); Insert(dis[i]); } printf("%d\n",ans); } return 0; }
原文地址:http://blog.csdn.net/ww140142/article/details/47052617