题目大意:给定一棵树,每条边都有对应的权值,在树上找一条简单的路径,使得所有边权值的异或值最大。
分析:这个类似于前边写过的一个数组选定两个数的最大异或值,先dfs预处理一下从1到i的异或值D[i],然后当你想要取到s到e的异或值就是D[s]^D[e]。接下来就相当于之前写过的两个数的最大异或值问题。求解最大异或值问题就是利用字典树,就可以高效的解决。
代码:
#include<iostream> #include<vector> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn=1e5+7; struct node{ int u,v,w,nt; }edge[maxn*4]; int tol; int head[maxn]; int trie[maxn*32][2]; int tot; bool vis[maxn]; int D[maxn]; void addEdge(int u,int v,int w){ edge[tol].u=u; edge[tol].v=v; edge[tol].w=w; edge[tol].nt=head[u]; head[u]=tol++; } void init(int n){ tot=1; tol=0; memset(vis,false,sizeof(vis)); memset(trie,0,sizeof(trie)); memset(D,0,sizeof(D)); memset(head,-1,sizeof(head)); } void dfs(int u){ vis[u]=true; for(int i=head[u];i!=-1;i=edge[i].nt){ int v=edge[i].v; if(vis[v]) continue; int w=edge[i].w; D[v]=D[u]^w; dfs(v); } } void insert(int x){ int p=1; for(int i=31;i>=0;i--){ int k=x>>i&1; if(!trie[p][k]) trie[p][k]=++tot; p=trie[p][k]; } } int search(int x){ int p=1; int ans=0; for(int i=31;i>=0;i--){ int k=x>>i&1; if(trie[p][!k]) ans|=(1<<i),p=trie[p][!k]; else p=trie[p][k]; } return ans; } int main(){ int n,u,v,w; while(scanf("%d",&n)!=EOF){ init(n); for(int i=0;i<n-1;i++){ scanf("%d%d%d",&u,&v,&w); addEdge(u,v,w); addEdge(v,u,w); } dfs(0); int ans=0; for(int i=0;i<n;i++){ ans=max(ans,search(D[i])); insert(D[i]); } printf("%d ",ans); } return 0; }