问题概括:求一棵带边权的树的一条最大Xor路径的值。
首先算出所有点到根路径的xor值并保存,这样任意两点路径的xor就可以用上述值互相xor表示(异或的基本性质)。
然后用所有值建一个Trie,位数强制31。对每个值在Trie上贪心即可,就是说尽量取反。
然而这题直接在Trie树上跑贪心会wa,而且大部分点都对了,不能理解。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
struct node{
int to,sum,fa,val;
};
int num=0,vis[100010]={0},value[100010];
int maxans=0;
vector<node> tree[100010];
void dfs(int fa,int sum){
for(int i=0;i<tree[fa].size();i++){
if(tree[fa][i].to!=fa&&vis[tree[fa][i].to]==0){
value[num]=tree[fa][i].val^sum;
num++;
vis[tree[fa][i].to]=1;
tree[fa][i].sum=tree[fa][i].val^sum;
tree[fa][i].fa=fa;
dfs(tree[fa][i].to,tree[fa][i].val^sum);
}
}
}
struct Trie{
int ch[4200010][2];
int val[4200010];
int sz;
Trie(){
sz=1;
memset(ch[0],0,sizeof(ch[0]));
}
void insert(int s,int v){
int u=0;
int k=0;
int bit[32]={0};
while(s>0){
bit[k++]=s&1; s>>=1;
}
for(int i=30;i>=0;i--){
int c=bit[i];
if(!ch[u][c]){
memset(ch[sz],0,sizeof(ch[sz]));
val[sz]=0;
ch[u][c]=sz++;
}
u=ch[u][c];
}
val[u]=v;
}
void solve(){
for(int i=0;i<num;i++){
int tmp=value[i];
int now=0;
int ans=0;
for(int j=30;j>=0;j--){
int bit=(tmp&(1<<(j)))>>j;
if(ch[now][1-bit]>0){
ans=ans|((1-bit)<<j);
now=ch[now][1-bit];
}
else if(ch[now][bit]>0){
ans=ans|(bit<<j);
now=ch[now][bit];
}
}
if((ans^tmp)>maxans)maxans=(ans^tmp);
}
}
void print(){
for(int i=0;i<sz;i++)cout<<i<<" "<<ch[i][0]<<" "<<ch[i][1]<<endl;
}
};
Trie t;
int main(){
int n;
scanf("%d",&n);
int x,y,z;
for(int i=1;i<=n-1;i++){
scanf("%d%d%d",&x,&y,&z);
node tmp;
tmp.sum=0;
tmp.val=z;
tmp.to=y;
tree[x].push_back(tmp);
tmp.to=x;
tree[y].push_back(tmp);
}
vis[1]=1;
dfs(1,0);
for(int i=0;i<num;i++)t.insert(value[i],1);
t.insert(0,1);
t.solve();
printf("%d\n",maxans);
return 0;
}