hdu4757 (可持久化Trie)

题目大意:给你一颗n个点的树,每个点有一个权值。然后有m个询问,问从x到y的简单路径中,权值 xor z最大是多少。

首先异或最大就是在字典树上找它的按位取反,首先满足高位。
思路:可持久化的0-1字典树,每个点在父节点的历史版本上新建一棵字典树,字典树上的每个结点给一个值记录从这个结点到树的根节点,有多少个权值会经过这个字典树上的结点。询问的时候在字典树上奏即可。由于a[i]<2^16,那么字典树的深度最大为16,空间复杂度为O(16 * n)。

算法理解:
首先ch[0][0],ch[0][1],v[0]的值一直是0,表示没有!
插入时:如果父节点中没有要找的值会y转向0结点!而x每次都会转向新建结点!(0结点是公共结点)


注意:结点从1开始,0结点用作没有值时的转向结点!

//#pragma comment(linker, "/STACK:102400000")
#include<cstdlib>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<set>
#include<map>
#include<list>
#include<queue>
#include<vector>
#define tree int o,int l,int r
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
#define lo o<<1
#define ro o<<1|1
#define pb push_back
#define mp make_pair
#define ULL unsigned long long
#define LL long long
#define inf 0x7fffffff
#define eps 1e-7
#define N 100009
using namespace std;
int m,n,T,t,x,y,u;
int val[N];
vector<int>g[N];
int p[N][19],c[N];
int v[2000000],ch[2000000][2],sz,root[N];
const int mc=19;

void init()
{
    sz=1;
    memset(p,-1,sizeof(p));
    for (int i=0; i<=n; ++i )
        g[i].clear();
}
int newnode()
{
    memset(ch[sz],0,sizeof(ch[sz]));
    v[sz]=0;
    return sz++;
}
void insert(int x,int y,int z)
{
    for(int i=15; i>=0; i--)
    {
        int c=(z>>(i))&1;//WA,只能取0,1

        ch[x][c]=newnode();
        ch[x][!c]=ch[y][!c];
        v[ch[x][c]]=v[ch[y][c]];
        x=ch[x][c],y=ch[y][c];

        v[x]++;
    }
}
void dfs(int u,int fa)
{
    p[u][0]=fa,c[u]=c[fa]+1;
    for(int i=1; i<mc&&p[u][i-1]!=-1; i++)
        p[u][i]=p[p[u][i-1]][i-1];
    root[u]=newnode();
    insert(root[u],root[fa],val[u]);
    for(int i=0; i<g[u].size(); i++)
    {
        int v=g[u][i];
        if(v!=fa)
        {
            dfs(v,u);
        }
    }
}
int lca(int a,int b)
{
    if(c[a]>c[b])
        swap(a,b);
    int t=c[b]-c[a];
    for(int i=0; i<mc&&t; i++)
        if(t&(1<<i))
        {
            b=p[b][i];
            t^=(1<<i);
        }
    if(a!=b)
    {
        for(int i=mc-1; i>=0; i--)
            if(p[a][i]!=p[b][i])
                a=p[a][i],b=p[b][i];
        a=p[a][0];
    }
    return a;
}
int query(int x,int y,int f,int s)
{
    int res=val[f]^s;
    f=root[f],x=root[x],y=root[y];
    int ans=0;//f会变值
    for(int i=15; i>=0; i--)
    {
        int c=!((s>>(i))&1);

        if(v[ch[x][c]]+v[ch[y][c]]-v[ch[f][c]]*2>0)
            ans|=(1<<i);
        else
            c=!c;
        x=ch[x][c],y=ch[y][c],f=ch[f][c];
    }
    return max(ans,res);
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("ex.in","r",stdin);
#endif
    int ncase=0;
    while(scanf("%d%d",&n,&m)==2)
    {
        init();
        for(int i=1; i<=n; i++)
            scanf("%d",&val[i]);
        for(int i=1; i<n; i++)
        {
            scanf("%d%d",&x,&y);
            g[x].pb(y);
            g[y].pb(x);
        }
        c[0]=0;
        dfs(1,0);//父亲节点必须是0!
        while(m--)
        {
            int s;
            scanf("%d%d%d",&x,&y,&s);
            int fa=lca(x,y);
            printf("%d\n",query(x,y,fa,s));
        }
    }
    return 0;
}
View Code

 

posted @ 2013-09-26 10:38  baoff  阅读(262)  评论(0编辑  收藏  举报