最大Xor路径 7.30 T2

题目描述
MT神牛非常喜欢出Xor的题,在WC2011的时候,MT神牛出了一道非常经典的Xor最大路径题。
Bird向MT神牛学习,思考了许多关于Xor路径的问题,有一天,Bird想到了一个问题,给出一个序列,求这个序列的连续子序列的Xor值最大。
如1 3 4 8,最大的Xor子序列当然是3 xor 4 xor 8=15了。
Bird实在太强大了,这个问题怎么能难住他呢?于是Bird又开始思考了,如果是一颗树呢,如何求出这棵带边权的树的一条最大Xor路径呢?但是谁都知道Bird实在太强大了,马上想到了解决这个问题的高效算法,但是Bird总是不愿去机房写代码,于是他把这个easy的问题,交给了你,希望你能尽快帮他写完代码。

输入
第一行,一个整数N,表示一颗树有N个节点,接下来N-1行,每行三个整数a,b,c表示节点a和节点b之间有条权值为c的边

输出
输出仅一行,即所求的带边权树的Xor最大路径。

样例输入
4
1 2 3
1 3 4
1 4 7
样例输出
7

提示
【数据规模】
对于40%的数据,数据退化为一条链
除上述的40%的数据外,还有10%的数据N<=1000
100%的数据满足2<=n<=100000, 1 < a,b<=N,C<=2^31-1

我们先考虑是一条链的情况:

F[i]iiji<jF[j]xorF[i]maxF[i]xorF[j]1<=i,j<=N.

然后我们考虑是树的情况:

类似于链,我们用F[i]表示根节点到i的异或和,显然i->j路径的异或和等价于F[i] xor F[j],这与链的情况无异。

所以题目就可以转化为给定N个数,求出这N个数中任意两个数xor的最大值。

具体做法:

在二进制中,越高位有1值越大,而异或运算只影响到当前位,所以越高位能异或成1就把它异或成1,于是我们将所有F[i]转为二进制当做字符串,按从高位到低位的顺序存入一颗字典树中,然后从最高位开始枚举,设当前数为x,当前枚举到二进制中第i位,x的第i位数字为j,当前在字典树中的k号节点,若k节点的j xor 1儿子存在,则当前答案的第i位为1,否则为0。时间复杂度(N*900)。
#include
#include
#include
#include
#define ll long long
using namespace std;
int n,x,y,z,tot,ans;
int a[35],head[100005],Next[200005],to[200005],len[200005],f[100005];
struct ty
{
    int Next[2];
    void init()
    {
        memset(Next,-1,sizeof(Next));
    }
}p[3100005];
void dfs(int k,int pre)
{
    for(int i=head[k];i!=-1;i=Next[i]) 
    if(to[i]!=pre) 
    {
        f[to[i]]=f[k]^len[i];
        dfs(to[i],k);
    }
}
void add(int x,int y,int z)
{
    tot++;
    Next[tot]=head[x];
    to[tot]=y;
    len[tot]=z;
    head[x]=tot;
}
void work(int x)
{
    int k=0;
    while(x>0) 
    {
        k++;
        a[k]=x%2;
        x=x/2;
    }
    for(int i=k+1;i<=31;i++) a[i]=0; 
}
void update()
{
    x=0;
    for(int i=31;i>=1;i--) 
    {
        int j=a[i];
        if(p[x].Next[j]==-1) 
        {
            tot++;
            p[x].Next[j]=tot;
            p[tot].init();
        }
        x=p[x].Next[j];
    }
}
int query()
{
    x=0;
    int s=0;
    for(int i=31;i>=1;i--) 
    {
        int j=a[i]^1;
        if(p[x].Next[j]==-1)  j=j^1;
        if((a[i]^j)==1) s=s+(1<<(i-1));
        x=p[x].Next[j];
    }
    return s;
}                
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++) head[i]=-1;
    for(int i=1;iscanf("%d%d%d",&x,&y,&z);
        add(x,y,z);
        add(y,x,z);
    }
    dfs(1,0);
    p[0].init();
    for(int i=1;i<=n;i++) 
    {
        work(f[i]);
        update();
    }
    for(int i=1;i<=n;i++) 
    {
        work(f[i]);
        ans=max(ans,query());
    }
    cout<return 0;
}

你可能感兴趣的:(noip2016训练)