1. 程式人生 > >最大Xor路徑 7.30 T2

最大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<j

F[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<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#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;i<n;i++) 
    {
        scanf("%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<<ans;
    return 0;
}