The XOR-longest Path(Bzoj1954)
试题描述
|
给定一棵 n 个点的带权树,求树上最长的异或和路径。
|
输入
|
多组数据。
每组数据第一行一个整数 n(1≤n≤10^5),接下来 n−1 行每行三个整数 u,v,w,表示 u,v 之间有一条长度为 w 的边。(0≤u,v<n,0≤w<2^31) |
输出
|
对于每组数据输出答案。
|
输入示例
|
4
1 2 3 2 3 4 2 4 6 |
输出示例
|
7
|
论一个人能sb到什么程度
写了半天发现多写了一个取反QAQ
日常被卡,这题的数据范围好像给错了
然后既然是关于异或的,我们肯定要想到Trie,将每条路径的异或和求出(首位补零)
然后在Trie树上跑一遍,尽量选择与它的当前为不同的
相加就可以了
下面给出代码:
#include<iostream> #include<cmath> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<algorithm> using namespace std; inline int rd(){ int x=0,f=1; char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1; for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0'; return x*f; } inline void write(int x){ if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10+'0'); return ; } int n; int trie[1000006][2]; int tot=1; int head[1000006]; int nxt[1000006]; int to[1000006]; int total=0; int v[1000006]; void add(int x,int y,int z){//邻接表连边 total++; to[total]=y; v[total]=z; nxt[total]=head[x]; head[x]=total; return ; } int a[1000006]; void pre(int x){ int c=1; for(int i=0;i<=30;i++){ a[i]=x&1; x>>=1; } reverse(a,a+31);//正序建树 补零 for(int i=0;i<=30;i++){ int s=a[i]; if(!trie[c][s]) trie[c][s]=++tot; c=trie[c][s]; } return ; } int num[1000006]; void dfs(int x,int fa){//计算每一条路径的异或和 for(int e=head[x];e;e=nxt[e]){ if(to[e]==fa) continue; num[to[e]]=num[x]^v[e]; dfs(to[e],x); } return ; } int check(int x){ int c=1; int sum=0; for(int i=0;i<=30;i++){ a[i]=x&1; x>>=1; } reverse(a,a+31); for(int i=0;i<=30;i++){ int s=a[i]; if(trie[c][!s]){//尽量选择不同的 让异或和最大 c=trie[c][!s]; sum+=(1<<30-i); } else c=trie[c][s]; } return sum; } int main(){ while(cin>>n){ memset(trie,0,sizeof(trie)); memset(num,0,sizeof(num)); memset(head,0,sizeof(head));//赋初值 total=0; tot=1; for(int i=1;i<n;i++){ int x=rd(),y=rd(),z=rd(); add(x,y,z); add(y,x,z); } dfs(1,0); for(int i=1;i<=n;i++) pre(num[i]); int ans=0; for(int i=1;i<=n;i++) ans=max(ans,check(num[i]));//取最大值 printf("%d",ans); } return 0; }
蒟蒻总是更懂你✿✿ヽ(°▽°)ノ✿