POJ3764The xor-longest Path 解题报告

题意简述:

给定一颗N个节点的树,树上的每一条边都有一个权值。从数中选择两个点x和y,把从x到y的路径上的所有边权xor(异或)起来,得到的结果最大是多少?

解题思路:

假设D[x]为从根节点到节点x路径权值的xor,那么很显然D[x] = D[father[x] ]。也就是说我们可以从树的根节点出发,通过一边dfs求出根到每个节点的D。而由于异或的特性,我们知道从节点x到节点y路径权值的xor,就是D[x] ^ D[y]。因为a^a = 0,所以“从根到节点x的路径权值xor” 与“从根到节点y的路径权值xor”刚好抵消。
于是我们就可以先通过一遍dfs求出每个节点的D,然后通过字典树来从这N个D中选出两个xor最大的,并输出。
注意事项:
首先数据范围很大,肯定不能用cin等慢读入。然后就是vector也很耗费时间,所以我们采用数组模拟树结构,采用“儿子+兄弟们”结构存树。还有就是别忘了怎么找父亲节点,这里采用将父节点的D通过参数传递。

代码示例:

#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++;
}
//要先dfs一次来求从根节点到该节点路径权值的xor和
void dfs(int p,int ww){
//这里要把当前父节点xor和作为参数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--){
        int ch = x>>k&1;
        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;
}
//初始化函数,用于多组测试用例
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;
}
int main(){
    int n,u,v,w;
    while(scanf("%d",&n) != EOF){
        int 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);//假设根节点为0
        
        for(int i = 0;i < n;i++){
            insert(D[i]);
            ans = max(ans,search(D[i]));
        }
        printf("%d\n",ans);
    }
    return 0;
}

参考书目:

  • 《算法竞赛进阶指南》李煜东.P73
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 程序猿惹谁了 设计师:白松林 返回首页