[HDU4757]Tree

题意

给定一颗 \(n\) 个点的树,每个点有一个点权。

先给出 \(m\) 组询问,每组询问给出一个三元组: \((x,y,z)\),表示:

询问在顶点 \(x\)\(y\) 的路径上(包括 \(x,y\) )的所有点权中与 \(z\) 异或产生的最大值。

题解

看到“异或产生的最大值”,应该敏锐地想到 Trie

但是一般的 01Trie 只能处理数集已经确定的情况下,然而此题询问的范围是不确定的。

因此需要 可持久化 Tire 来解决这个问题。

定义: \(S_x\) 表示从根节点到 \(x\) 顶点的路径(包括两端)上的 前缀 Trie 树。即这个 Trie 树 中保存了这条路径上所有节点的权值信息。

那么这么得到询问所给路径的权值信息的 Trie 树呢?

我们有这样一个公式:

\[S_{\text{所求}} = S_x + S_y - S_p - S_q\]

其中 \(p=\operatorname{LCA}(x,y),q=\operatorname{father}(p)\)

结合一张图理解一下:

3yHtoj.png

那么询问就很好写了:

int calc(int a,int b,int s,int t,int val)
{//询问要求a->b的路径,s=LCA(a,b),t=father(s),val是询问给定的值
    int ret=0;//结果
    for(register int i=Bit;~i;i--)//从高到低枚举每一位
    {
        int c=(val>>i)&1;//当前位
        if(cnt[ch[a][!c]]+cnt[ch[b][!c]]>cnt[ch[s][!c]]+cnt[ch[t][!c]])//若真实所求的 Trie 树中含有一条不同于当前位的路径
            ret|=(1<<i),c^=1;//加入答案,并重新设置下一个要走的位置
        a=ch[a][c],b=ch[b][c],s=ch[s][c],t=ch[t][c];//四个点都要走下去
    }
    return ret;//返回答案
}

把初始化操作也提一下(LCA略去):

int insert(int pre,int val)
{//上一个版本的根节点为pre,插入值为val
    int rt=++total;
    int now=rt;//新开根节点,这里不更新cnt没事是因为询问会忽略根。
    for(register int i=Bit;~i;i--)//从高到低枚举每一位
    {
        int c=(val>>i)&1;//当前为
        ch[now][c]=++total;//当前位新开结点
        ch[now][!c]=ch[pre][!c];//非当前位直接复制上个版本的
        now=ch[now][c],pre=ch[pre][c];//走下去
        cnt[now]=cnt[pre]+1;//更新cnt值
    }
    return rt;//别忘了返回新根结点的编号。
}

void Dfs3(int rt,int f)//初始化用Dfs实现(Dfs1,2用来处理树剖lca了)
{
    root[rt]=insert(root[f],w[rt]);//在父结点信息的基础上更新上当前结点的权值
    for(register int i=0;i<int(G[rt].size());i++)
        if(G[rt][i]!=f) Dfs3(G[rt][i],rt);//Dfs下一层
}

最后贴一下完整代码:

#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;

const int N=1e5+5;

int n,q,w[N];
vector<int> G[N];

int fa[N],size[N];
int dep[N],maxs[N];
int top[N];

void Dfs1(int rt,int f)
{
    fa[rt]=f,dep[rt]=dep[f]+1,size[rt]=1;
    for(register int i=0;i<int(G[rt].size());i++)
    {
        int nxt=G[rt][i];
        if(nxt==f) continue;
        Dfs1(nxt,rt);
        size[rt]+=size[nxt];
        if(size[maxs[rt]]<size[nxt]) maxs[rt]=nxt;
    }
}

void Dfs2(int rt,int tp)
{
    top[rt]=tp;
    if(size[rt]>1) Dfs2(maxs[rt],tp);
    for(register int i=0;i<int(G[rt].size());i++)
        if(G[rt][i]!=fa[rt]&&G[rt][i]!=maxs[rt])
            Dfs2(G[rt][i],G[rt][i]);
}

int get_lca(int u,int v)
{
    while(top[u]!=top[v])
        (dep[top[u]]>=dep[top[v]])?u=fa[top[u]]:v=fa[top[v]];
    return (dep[u]<dep[v])?u:v;
}

const int Bit=16;
const int SZ=2e6+5;
int ch[SZ][2];
int cnt[SZ];
int total=1;
int root[N];

int insert(int pre,int val)
{
    int rt=++total;
    int now=rt;
    for(register int i=Bit;~i;i--)
    {
        int c=(val>>i)&1;
        ch[now][c]=++total;
        ch[now][!c]=ch[pre][!c];
        now=ch[now][c],pre=ch[pre][c];
        cnt[now]=cnt[pre]+1;
    }
    return rt;
}

void Dfs3(int rt,int f)
{
    root[rt]=insert(root[f],w[rt]);
    for(register int i=0;i<int(G[rt].size());i++)
        if(G[rt][i]!=f) Dfs3(G[rt][i],rt);
}

int calc(int a,int b,int s,int t,int val)
{
    int ret=0;
    for(register int i=Bit;~i;i--)
    {
        int c=(val>>i)&1;
        if(cnt[ch[a][!c]]+cnt[ch[b][!c]]>cnt[ch[s][!c]]+cnt[ch[t][!c]])
            ret|=(1<<i),c^=1;
        a=ch[a][c],b=ch[b][c],s=ch[s][c],t=ch[t][c];
    }
    return ret;
}

void solve()
{
    for(register int i=1;i<=n;i++)
        scanf("%d",w+i),G[i].clear();
    for(register int i=1,u,v;i<n;i++)
    {
        scanf("%d%d",&u,&v);
        G[u].push_back(v),G[v].push_back(u);
    }

    memset(fa,0,sizeof(fa));
    memset(size,0,sizeof(size));
    memset(dep,0,sizeof(dep));
    memset(top,0,sizeof(top));
    memset(maxs,0,sizeof(maxs));
    Dfs1(1,0);
    Dfs2(1,1);
    
    memset(root,0,sizeof(root));
    memset(ch,0,sizeof(ch));
    memset(cnt,0,sizeof(cnt));
    total=1;
    Dfs3(1,0);
    
    while(q--)
    {
        int u,v,k;
        scanf("%d%d%d",&u,&v,&k);
        int lca=get_lca(u,v),fl=fa[lca];
        int ans=calc(root[u],root[v],root[lca],root[fl],k);
        printf("%d\n",ans);
    }
}

signed main()
{
    while(~scanf("%d%d",&n,&q))
        solve();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/-Wallace-/p/12384881.html