这道题其实可以用01Trie树来解决。平时我们所用的Trie树都是插入字符,而这里的Trie树只用0和1来表示,就成了一棵二叉树。最大的异或和实际上就是两个点到根节点异或和的异或和的最大值。
先dfs预处理出所有节点到根节点的异或和,在用这些异或和建一棵Trie树,最后在Trie树上贪心。对于一个数表示成二进制的每一位,我们尽量让它去异或与那一位上的值相反的值(0ˆ1,1ˆ0)枚举每一个数在Trie树上的前缀异或和,取个max即为最后的答案。
代码如下:
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn=1e6+7; struct node{ int nxt; int to; int value; }tree[maxn*3]; int sum[maxn]; int n; int head[maxn],cnt; int tr[maxn][2]; int tot=1,rt; int len; int save; int ans; void add(int x,int y,int v){ tree[++cnt].nxt=head[x]; tree[cnt].to=y; tree[cnt].value=v; head[x]=cnt; } int x,y,v; void Trie(){ rt=1; for(int i=(1<<30);i;i>>=1){ bool c=save&i;//取出那一位 if(!tr[rt][c]) tr[rt][c]=++tot; rt=tr[rt][c]; } } int get(){ int res=0; rt=1; for(int i=(1<<30);i;i>>=1){ bool c=save&i; if(tr[rt][c^1]){ res+=i; rt=tr[rt][c^1]; } else rt=tr[rt][c]; } return res; } void dfs(int x,int fa){ if(!x) return; for(int i=head[x];i;i=tree[i].nxt){ int go=tree[i].to; sum[go]=sum[x]^tree[i].value; if(go==fa) continue; dfs(go,x); } } int main(){ scanf("%d",&n); for(int i=1;i<n;i++){ scanf("%d%d%d",&x,&y,&v); add(x,y,v);add(y,x,v); } sum[1]=0; dfs(1,0); for(int i=1;i<=n;i++){ save=sum[i]; Trie(); } for(int i=1;i<=n;i++){ save=sum[i]; int ljb=get(); ans=max(ans,ljb); } printf("%d\n",ans); return 0; }
原文地址:https://www.cnblogs.com/LJB666/p/11185123.html
时间: 2024-11-06 11:27:10