The xor-longest Path
题目大意:给定一颗N个节点的树,树上的每一条边都有一个权值。从数中选择两个点x和y,把从x到y的路径上的所有边权xor(异或)起来,得到的结果最大是多少?
解题思路:
因为 a ^ b==(a ^ c) ^ (b ^ c), 即两个点到根的异或和异或一下就是这两个点之间的异或和,根据这条性质,我们可以从根节点(也就是前文中的 C )开始跑一遍 dfs 记录下当前节点到根节点的异或和,然后转成01串插入到trie树里面,最后按照贪心思想匹配的时候尽可能的匹配与当前位不同的即可。
Code:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAXN = 100100;
int t[MAXN*33][3],tot = 1,D[MAXN];
int head[MAXN],cnt = 1;
bool vis[MAXN];
//因为用vector会超时,所以我们采用数组来存贮树结构,儿子+兄弟们 ----> 链式前向星
struct Edge{
int to,val,brh;
Edge(){}
Edge(int to,int val,int brh):to(to),val(val),brh(brh){}
}edges[MAXN*4];
void addEdge(int from,int to,int val){ //无向边建图
edges[cnt] = Edge(to,val,head[from]);
head[from] = cnt++;
}
void init(){
memset(head,-1,sizeof head);
memset(vis,false,sizeof vis);
memset(t,0,sizeof t);
memset(D,0,sizeof D);
cnt = tot = 1;
}
void dfs(int p,int ww){ //记录当前节点到根节点的异或和
vis[p] = true;
D[p] = ww;
for(int i = head[p];i != -1;i = edges[i].brh){
if(!vis[edges[i].to])
dfs(edges[i].to,ww^edges[i].val);
}
}
void insert(int x){ //插入到字典树
int p = 1;
for(int k = 30;k >= 0;k--){ //转换成01串
int ch = x>>k&1; // if(x&(1<<i)) ch=1; else ch=0;
if(t[p][ch]==0){
t[p][ch]=++tot;
}
p = t[p][ch];
}
}
int search(int x){
int p = 1,ans = 0;
for(int k = 30;k >= 0;k--){
int ch = x>>k&1;
if(t[p][!ch]){ //尽可能找不一样的,贪心思想
p = t[p][!ch];
ans |= 1<<k;
}else p = t[p][ch];
}
return ans;
}
int main(){
int n,u,v,w,ans;
while(~scanf("%d",&n)){
ans=0;
init();
for(int i =1;i<n;i++){
scanf("%d%d%d",&u,&v,&w);
addEdge(u,v,w);
addEdge(v,u,w);
}
dfs(0,0);
for(int i=0;i<n;i++) insert(D[i]);
for(int i=0;i<n;i++) ans=max(ans,search(D[i]));
printf("%d\n",ans);
}
return 0;
}