可持久化01Trie樹+LCA【p4592】[TJOI2018]異或

Description

如今有一顆以\(1\)爲根節點的由\(n\)個節點組成的樹,樹上每一個節點上都有一個權值\(v_i\)。如今有\(Q\)次操做,操做以下:ios

  • 1\(\;x\;y\):查詢節點\(x\)的子樹中與\(y\)異或結果的最大值
  • 2\(\;x\;y\;z\):查詢路徑\(x\)\(y\)上點與\(z\)異或結果最大值

Input

第一行是兩個數字\(n,Q\);git

第二行是\(n\)個數字用空格隔開,第\(i\)個數字\(v_i\)表示點\(i\)上的權值spa

接下來\(n-1\)行,每行兩個數,\(x,y\),表示節點\(x\)\(y\)之間有邊code

接下來\(Q\)行,每一行爲一個查詢,格式如上所述.ip

Output

對於每個查詢,輸出一行,表示知足條件的最大值。get

表示不太會可持久化\(01Trie\)input

參考着題解碼了出來,仍是有點不懂.it

可是又感受懂得差很少。io

這個題差很少能夠本身碼出來,很好的一個題。ast

可持久化\(01Trie\)思想還行,相似於主席樹思想.

用到了\(lastroot\).

對於如今的本身,不太想深究具體構造,感受網上講解的這個不是很好。

打算活過\(NOIP\)以後寫一篇講解。

代碼

#include<cstdio>
#include<iostream>
#include<algorithm>
#define R register

using namespace std;

const int maxn= 1e5+8;

inline void in(int &x)
{
    int f=1;x=0;char s=getchar();
    while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
    while(isdigit(s)){x=x*10+s-'0';s=getchar();}
    x*=f;
}

struct Trie
{
    int root[maxn],ch[maxn*35][2],tot,cnt[maxn*35];
    Trie(){root[0]=tot=1;}
    inline void insert(int lastroot,int &nowroot,int x)
    {
        nowroot=++tot;
        int u=nowroot;
        for(R int i=30;~i;i--)
        {
            R int bit=(x>>i)&1;
            ch[u][!bit]=ch[lastroot][!bit];
            ch[u][bit]=++tot;
            u=ch[u][bit];
            lastroot=ch[lastroot][bit];
            cnt[u]=cnt[lastroot]+1;
        }
    }
    
    inline int query(int l,int r,int x)
    {
        int res=0;
        for(R int i=30;~i;i--)
        {
            R int bit=(x>>i)&1;
            if(cnt[ch[r][!bit]]-cnt[ch[l][!bit]])
            {
                r=ch[r][!bit];
                l=ch[l][!bit];
                res+=(1<<i);
            }
            else
            {
                r=ch[r][bit];
                l=ch[l][bit];
            }
        }
        return res;
    }
}tr,se;

int dfn[maxn],fdfn[maxn],val[maxn],idx,depth[maxn];

int head[maxn],tot,l[maxn],r[maxn],size[maxn];
struct cod{int u,v;}edge[maxn<<1];

inline void add(R int x,R int y)
{
    edge[++tot].u=head[x];
    edge[tot].v=y;
    head[x]=tot;
}

int f[maxn][21];

void dfs(R int u,R int fa)
{
    tr.insert(tr.root[fa],tr.root[u],val[u]);
    f[u][0]=fa;depth[u]=depth[fa]+1;
    dfn[u]=++idx,fdfn[idx]=u;size[u]=1;
    for(R int i=1;(1<<i)<=depth[u];i++)
        f[u][i]=f[f[u][i-1]][i-1];
    for(R int i=head[u];i;i=edge[i].u)
    {
        if(edge[i].v==fa)continue;
        dfs(edge[i].v,u);
        size[u]+=size[edge[i].v];
    }
}

inline int lca(R int x,R int y)
{
    if(depth[x]>depth[y])swap(x,y);
    for(R int i=17;~i;i--)
        if(depth[x]+(1<<i)<=depth[y])
            y=f[y][i];
    if(x==y)return y;
    for(R int i=17;~i;i--)
    {
        if(f[x][i]==f[y][i])continue;
        x=f[x][i],y=f[y][i];
    }
    return f[x][0];
}

int n,q;

int main()
{
    in(n),in(q);
    for(R int i=1;i<=n;i++)in(val[i]);
    for(R int i=1,x,y;i<n;i++)
    {
        in(x),in(y);
        add(x,y),add(y,x);
    }
    dfs(1,0);
    for(R int i=1;i<=n;i++)
        se.insert(se.root[i-1],se.root[i],val[fdfn[i]]);
    for(R int opt,x,y,z;q;q--)
    {
        in(opt);
        if(opt==1)
        {
            in(x),in(y);
            printf("%d\n",se.query(se.root[dfn[x]-1],se.root[dfn[x]+size[x]-1],y));
        }
        else
        {
            in(x),in(y),in(z);
            int la=lca(x,y);
            printf("%d\n",max(tr.query(tr.root[f[la][0]],tr.root[x],z),tr.query(tr.root[f[la][0]],tr.root[y],z)));
        }
    }
}
相關文章
相關標籤/搜索