HDU4757 Tree(可持久化Trie)

写过可持久化线段树,但是从来没写过可持久化的Trie,今天补一补。

题目就是典型的给你一个数x,和一个数集,问x和里面的某个数xor起来的最大值是多少。

最原始的是数集是固定的,只需要对数集按照高到低位去建Trie,然后贪心匹配就可以了。

这里则是对树上路径的操作,其实也是一样的,对每个节点x维护root到x的Trie,然后纪录下往左走往右走的叶子节点个数,设z=lca(x,y),那么到了个某个节点能否往某个儿子走的限制条件是 sz[ch[x][c]]+sz[ch[y][c]]-2*sz[ch[z][c]]>0,这样说明下面是存在c的儿子的,接着往下走即可。当然这样算其实是会漏掉lca的,所以最后还要和lca取最大值。

区间的询问作为这题的特例同理也是可以处理的。

#include <iostream>

#include <cstdio>

#include <cstring>

#include <string>

#include <algorithm>

#include <cmath>

#include <queue>

#include <cassert>

#include <vector>

#include <set>

using namespace std;



#define maxn 120000

#define maxnode 2200000

#define maxlogv 16

vector<int> G[maxn];

int n,m;

int a[maxn];



int f[maxlogv+2][maxn];

int dep[maxn];

int ch[maxnode][2];

int sz[maxnode];

int tot;

int root[maxn];



int newnode(){

    memset(ch[tot],0,sizeof(ch[tot]));

    sz[tot]=0;

    return tot++;

}



// insert val for x with father as y

void insert(int x,int y,int val)

{

    x=root[x];y=root[y];

    for(int i=15;i>=0;--i){

        int c=(val>>i)&1;

        if(!ch[x][c]){

            int id=newnode();

            ch[x][c]=id;

            ch[x][!c]=ch[y][!c];

            sz[ch[x][c]]=sz[ch[y][c]];

        }

        x=ch[x][c],y=ch[y][c];

        ++sz[x];

    }

}



void dfs(int u,int fa)

{

    f[0][u]=fa;dep[u]=dep[fa]+1;

    root[u]=newnode();

    insert(u,fa,a[u]);

    for(int i=0;i<G[u].size();++i){

        int v=G[u][i];

        if(v==fa) continue;

        dfs(v,u);

    }

}



int lca(int u,int v)

{

    if(dep[u]>dep[v]) swap(u,v);

    for(int k=0;k<maxlogv;++k){

        if( (dep[v]-dep[u])>>k&1){

            v=f[k][v];

        }

    }

    if(u==v) return u;

    for(int k=maxlogv-1;k>=0;--k){

        if(f[k][u]!=f[k][v]){

            u=f[k][u];

            v=f[k][v];

        }

    }

    return f[0][u];

}



int query(int x,int y,int val)

{

    int z=lca(x,y);int res=a[z]^val;

    x=root[x],y=root[y],z=root[z];

    int ret=0;

    for(int i=15;i>=0;--i){

        int c=(val>>i)&1;

        if(sz[ch[x][!c]]+sz[ch[y][!c]]-2*sz[ch[z][!c]]>0){

            ret+=1<<i;

            c=!c;

        }

        x=ch[x][c];

        y=ch[y][c];

        z=ch[z][c];

    }

    return max(ret,res);

}





int main()

{

    while(cin>>n>>m){

        for(int i=1;i<=n;++i){

            scanf("%d",a+i);

            G[i].clear();

        }

        int ui,vi;

        for(int i=0;i<n-1;++i){

            scanf("%d%d",&ui,&vi);

            G[ui].push_back(vi);

            G[vi].push_back(ui);

        }

        memset(root,0,sizeof(root));

        tot=1;

        memset(f,0,sizeof(f));

        memset(sz,0,sizeof(sz));

        dep[0]=0;

        dfs(1,0);

        for(int k=0;k+1<maxlogv;++k){

            for(int v=1;v<=n;++v){

                if(f[k][v]==0) f[k+1][v]=0;

                else f[k+1][v]=f[k][f[k][v]];

            }

        }

        int xi,yi,zi;

        for(int i=0;i<m;++i){

            scanf("%d%d%d",&xi,&yi,&zi);

            printf("%d\n",query(xi,yi,zi));

        }

    }

    return 0;

}

 

你可能感兴趣的:(tree)