hdu4757 (可持久化字典树+LCA)

题意

给一棵树,每个节点有权值。每次询问要求回答一个值异或某条路径上的一个点的最大值。

思路

我们可以对每一个点开一个字典树,记录从这个点到根的路径上的所有数,然后求两点的LCA,然后把路径分成左端点到LCA的路和右端点到LCA的路来做。

#include<bits/stdc++.h>
using namespace std;
const int maxx = 1e5+10;
struct node
{
    int to,next;
}e[maxx*2];
int head[maxx],cnt;
int depth[maxx],fa[maxx][22],lg[maxx];
int trie[20*maxx][2],sum[20*maxx],val[20*maxx],tot;
int rt[maxx];
int a[maxx];
void add(int u,int v)
{
    e[++cnt].to=v;
    e[cnt].next=head[u];
    head[u]=cnt;
}
void update(int u,int v,int x)
{
    rt[u]=++tot;
    int now=rt[u],pre=rt[v];
    for(int i=16;i>=0;i--)
    {
        int id=(x>>i)&1;
        trie[now][id]=++tot;
        trie[now][id^1]=trie[pre][id^1];
        now=trie[now][id];
        pre=trie[pre][id];
        sum[now]=sum[pre]+1;
    }
    val[now]=x;
}
int query(int l,int r,int x)
{
    for(int i=16;i>=0;i--)
    {
        int id=(x>>i)&1;
        if(sum[trie[r][id^1]]>sum[trie[l][id^1]])
            r=trie[r][id^1],l=trie[l][id^1];
        else r=trie[r][id],l=trie[l][id];
    }
    return val[r]^x;
}
void dfs(int f,int fath)
{
    update(f,fath,a[f]);
    depth[f]=depth[fath]+1;
    fa[f][0]=fath;
    for(int i=1;(1<<i)<=depth[f];i++)
        fa[f][i]=fa[fa[f][i-1]][i-1];
    for(int i=head[f];i;i=e[i].next)
        if(e[i].to!=fath)dfs(e[i].to,f);
}
int lca(int x,int y)
{
    if(depth[x]<depth[y])swap(x,y);
    while(depth[x]>depth[y])
        x=fa[x][lg[depth[x]-depth[y]]-1];
    if(x==y)return x;
    for(int k=lg[depth[x]]-1;k>=0;k--)
        if(fa[x][k]!=fa[y][k])x=fa[x][k],y=fa[y][k];
    return fa[x][0];
}
void init()
{
    memset(head,0,sizeof(head));
    tot=cnt=0;
    memset(depth,0,sizeof(depth));
    memset(fa,0,sizeof(fa));
    memset(trie,0,sizeof(trie));
    memset(sum,0,sizeof(sum));
    memset(lg,0,sizeof(lg));
    memset(rt,0,sizeof(rt));
    memset(val,0,sizeof(val));
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        init();
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        int u,v;
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&u,&v);
            add(u,v);add(v,u);
        }
        rt[0]=++tot;
        dfs(1,0);
        for(int i=1;i<=n;i++)
            lg[i]=lg[i-1]+(1<<lg[i-1]==i);
        int w;
        while(m--)
        {
            scanf("%d%d%d",&u,&v,&w);
            int la=lca(u,v);
            int ans=a[la]^w;
            if(la!=u)ans=max(query(rt[la],rt[u],w),ans);//避免空区间
            if(la!=v)ans=max(query(rt[la],rt[v],w),ans);
            printf("%d\n",ans);
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/HooYing/p/12459922.html