POJ - 3764 The xor-longest Path(树上两点路径边权异或和,01字典树)

链接:POJ - 3764 The xor-longest Path

题意:

给出一棵 n ( 1 n 100000 ) n(1\le n\le100000) 个结点的树,每条边具有边权 w ( 0 w 2 31 ) w(0\le w\le 2^{31}) ,结点编号从 0 0 n 1 n-1 。要求求出 异或和最大的路径(即路径上所有边权 w w 异或和最大),所有结点均可作为起点、终点。



分析:

图源自网络
由于异或的性质,其实只需要 任选一点作为根结点,如上图的 A A ,然后 DFS算得所有其他点到A点的异或和 s u m A X sum_{A-X} 即可。

那么则有,任意两个点路径上的异或和 s u m X Y = s u m A X s u m A Y sum_{X-Y}=sum_{A-X}\oplus sum_{A-Y}

因为异或时,相同部分的路径边权 w w 相同,异或得 0 0 ,不相同部分相互异或,最后与 0 0 异或,不变。

例如 F F J J 路径上的边权异或和 s u m F J sum_{F-J}

s u m A F = w A C w C F sum_{A-F}=w_{A-C}\oplus w_{C-F}
s u m A J = w A C w C E w E J sum_{A-J}=w_{A-C}\oplus w_{C-E}\oplus w_{E-J}


      s u m A F s u m A J = ( w A C w C F ) ( w A C w C E w E J ) \implies sum_{A-F}\oplus sum_{A-J}=(w_{A-C}\oplus w_{C-F})\oplus (w_{A-C}\oplus w_{C-E}\oplus w_{E-J})
= ( w A C w A C ) ( w C F w C E w E J ) = 0 ( w C F w C E w E J ) = (w_{A-C}\oplus w_{A-C})\oplus(w_{C-F}\oplus w_{C-E}\oplus w_{E-J})=0\oplus(w_{C-F}\oplus w_{C-E}\oplus w_{E-J})
= w C F w C E w E J = s u m F J =w_{C-F}\oplus w_{C-E}\oplus w_{E-J}=sum_{F-J}


综上,该题只需要DFS一次,每次遍历到一个结点X就先在01字典树中找到与 s u m A X sum_{A-X} 异或最大的,然后把 s u m A X sum_{A-X} 放入01字典树中即可。



以下代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=1e6+50;
const int max_base=31;
int n;
struct edge
{
    int u;
    int v;
    int w;
    int next;
}e[maxn<<1];
int head[maxn],s,cnt;
void addedge(int u,int v,int w)
{
    e[cnt]=edge{u,v,w,head[u]};
    head[u]=cnt++;
    e[cnt]=edge{v,u,w,head[v]};
    head[v]=cnt++;
}
int ch[31*maxn][2],val[31*maxn],tot;
void init()
{
    memset(head,-1,sizeof(head));
    cnt=0;

    tot=1;
    ch[0][0]=ch[0][1]=0;
    val[0]=0;
}
void ins(int x)
{
    int u=0;
    for(int i=max_base;i>=0;i--)
    {
        int cur=(x>>i)&1;
        if(!ch[u][cur])
        {
            ch[tot][0]=ch[tot][1]=0;
            val[tot]=0;
            ch[u][cur]=tot++;
        }
        u=ch[u][cur];
    }
    val[u]=x;
}
int query_max(int x)
{
    int u=0;
    for(int i=max_base;i>=0;i--)
    {
        int cur=(x>>i)&1;
        if(ch[u][cur^1])
            u=ch[u][cur^1];
        else
            u=ch[u][cur];
    }
    return x^val[u];
}
int ans;
void dfs(int u,int pre,int sum)
{
    ans=max(ans,query_max(sum));
    ins(sum);
    for(int i=head[u];i!=-1;i=e[i].next)
    {
        if(e[i].v!=pre)
            dfs(e[i].v,u,sum^e[i].w);
    }
}
int main()
{
    while(~scanf("%d",&n))
    {
        init();
        for(int i=1;i<=n-1;i++)
        {
            int u,v,w;
            scanf("%d %d %d",&u,&v,&w);
            addedge(u,v,w);
        }
        ans=0;
        dfs(0,-1,0);
        printf("%d\n",ans);
    }
    return 0;
}
发布了214 篇原创文章 · 获赞 40 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/Ratina/article/details/98967033