P4551 最长异或路径 题解
淦,异或的性质必须要熟悉啊!!!不看题解就想不到,一看题解就啥都会了)
一个完美的性质:$a\oplus b\oplus b=a$
于是,对于一个路径$d(x,y)$,必然有$d(x,y)=d(x,root)\oplus d(root,y)$,其中$d(x,y)$表示x到y路径的异或和
接着正解就呼之欲出了:
对于每一个节点$u$,我们均可以计算出其到根节点的异或和,而答案就是$\sum_{i!=j}max\{d(i,root)\oplus d(j,root)\}$
我去这么简单
接下来利用trie树即可完成剩余问题。
什么?没有听说过怎么用trie树求任意两个数的异或最大值,只知道给定一个数求它异或其他数的最大值?(这不就是我吗)
想这么多干啥,trie树一次时间复杂度也就是30左右的大常数,直接把每一个数全部拿来试试不就可以了?
(CaO)
打代码的时候出现了一点错误调试了很久,以此警示自己:trie树cnt初始值要设为1!!!已经有根节点了!!!!!!!!!
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; inline int r() { int s=0,k=1;char c=getchar(); while(!isdigit(c)) { if(c=='-')k=-1; c=getchar(); } while(isdigit(c)) { s=s*10+c-'0'; c=getchar(); } return s*k; } int n,head[1000001],cnt; int s[35]; int ccnt,maxi,tr[10000001][2],f[1000001],tcnt; struct node { int to,next,dis; }a[1000001]; void add_edge(int from,int to,int dis) { a[++cnt].to=to; a[cnt].dis=dis; a[cnt].next=head[from]; head[from]=cnt; } void update(int x) { memset(s,0,sizeof(s)); ccnt=0; while(x) { if(x&1)s[++ccnt]=1; else s[++ccnt]=0; x>>=1; } } void add(int x) { if(!x)return; update(x); int now=1; for(int i=maxi;i;i--) { int u=s[i]; if(!tr[now][u]) tr[now][u]=++tcnt; now=tr[now][u]; } } void dfs(int u,int fa,int now) { f[u]=now; maxi=max(maxi,now); for(int i=head[u];i;i=a[i].next) { int v=a[i].to; if(v!=fa)dfs(v,u,now^a[i].dis); } } int sum(int x) { update(x); int now=1,mx=0; for(int i=maxi;i;i--) { int u=s[i]; if(tr[now][u^1])// { now=tr[now][u^1]; mx=mx*2+1; } else { now=tr[now][u]; mx*=2; } } return mx; } signed main() { tcnt++; n=r(); int x,y,z; for(int i=1;i<n;i++) { x=r();y=r();z=r(); add_edge(x,y,z); add_edge(y,x,z); } dfs(1,1,0); update(maxi); maxi=ccnt; int ans=0; for(int i=1;i<=n;i++)add(f[i]); for(int i=1;i<=n;i++) { // cout<<"i:"<<i<<" "<<f[i]<<' '<<sum(f[i])<<endl; ans=max(ans,sum(f[i])); } cout<<ans; }
本文来自博客园,作者:lei_yu,转载请注明原文链接:https://www.cnblogs.com/lytql/p/15001992.html