1. 程式人生 > >洛谷 P4592 [TJOI2018]異或 解題報告

洛谷 P4592 [TJOI2018]異或 解題報告

P4592 [TJOI2018]異或

題目描述

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

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

  • 2 x y:查詢路徑\(x\)\(y\)上點與\(z\)異或結果最大值

輸入輸出格式

輸入格式:

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

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

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

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

輸出格式:

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

說明

對於\(10\%\)的資料,有\(1<n,Q\leq100\)

對於\(20\%\)的資料,有\(1<n,Q\leq1000\)

對於\(40\%\)的資料,有\(1<n,Q\leq10000\)

對於\(100\%\)的資料,有\(1<n,Q\leq100000\)

對於\(100\%\)的資料,有查詢\(1\)中的\(y\leq2^{30}\),查詢\(2\)中的\(z\leq2^{30}\)


區間異或最大值可以用可持久化字典樹實現。

這個題建對DFS序建一顆,對自根向下的鏈建,分別處理兩種詢問就可以了。


Code:

#include <cstdio>
#include <cctype>
const int N=1e5+10;
int read()
{
    int x=0;char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) {x=x*10+c-'0';c=getchar();}
    return x;
}
int max(int x,int y){return x>y?x:y;}
#define ls ch[now][0]
#define rs ch[now][1]
#define rep(i,a,b) for(int i=a;i<=b;i++)
int head[N],to[N<<1],Next[N<<1],cnt;
void add(int u,int v)
{
    to[++cnt]=v,Next[cnt]=head[u],head[u]=cnt;
}
int poi[N],n,Q;
namespace work1//子樹
{
    int ch[N*32][2],mx[N*32],tot,dfn[N],low[N],ha[N],dfsclock,root[N];
    void dfs(int now,int fa)
    {
        dfn[now]=++dfsclock;
        ha[dfsclock]=now;
        for(int i=head[now];i;i=Next[i])
            if(to[i]!=fa)
                dfs(to[i],now);
        low[now]=dfsclock;
    }
    void Insert(int las,int &now,int dep,int id)
    {
        if(!now) now=++tot;
        if(dep<0){mx[now]=id;return;}
        int bit=poi[ha[id]]>>dep&1;
        Insert(ch[las][bit],ch[now][bit],dep-1,id);
        ch[now][bit^1]=ch[las][bit^1];
        mx[now]=max(mx[ls],mx[rs]);
    }
    void init()
    {
        dfs(1,0);
        rep(i,1,n) Insert(root[i-1],root[i],30,i);
    }
    int query(int now,int les,int dep,int x)
    {
        if(dep<0) return x^poi[ha[mx[now]]];
        int bit=x>>dep&1;
        if(mx[ch[now][bit^1]]>=les) return query(ch[now][bit^1],les,dep-1,x);
        return query(ch[now][bit],les,dep-1,x);
    }
    void work()
    {
        int x=read(),y=read();
        printf("%d\n",query(root[low[x]],dfn[x],30,y));
    }
}
namespace work2
{
    int f[N][20],ch[N*32][2],mx[N*32],root[N],dep[N],en[N*32],tot,tmp;
    void swap(int &x,int &y){tmp=x,x=y,y=tmp;}
    void Insert(int las,int &now,int de,int id)
    {
        if(!now) now=++tot;
        if(de<0){mx[now]=dep[id],en[now]=id;return;}
        int bit=poi[id]>>de&1;
        Insert(ch[las][bit],ch[now][bit],de-1,id);
        ch[now][bit^1]=ch[las][bit^1];
        mx[now]=max(mx[ls],mx[rs]);
    }
    void dfs(int now)
    {
        for(int i=1;f[now][i-1];i++) f[now][i]=f[f[now][i-1]][i-1];
        for(int i=head[now];i;i=Next[i])
        {
            int v=to[i];
            if(v==f[now][0]) continue;
            dep[v]=dep[now]+1;
            f[v][0]=now;
            Insert(root[now],root[v],30,v);
            dfs(v);
        }
    }
    void init()
    {
        dep[1]=1;
        Insert(0,root[1],30,1);
        dfs(1);
    }
    int LCA(int x,int y)
    {
        if(dep[x]<dep[y]) swap(x,y);
        for(int i=18;~i;i--)
            if(dep[f[x][i]]>=dep[y])
                x=f[x][i];
        if(x==y) return x;
        for(int i=18;~i;i--)
            if(f[x][i]!=f[y][i])
                x=f[x][i],y=f[y][i];
        return f[x][0];
    }
    int query(int now,int les,int de,int x)
    {
        if(de<0) return poi[en[now]]^x;
        int bit=x>>de&1;
        if(mx[ch[now][bit^1]]>=les) return query(ch[now][bit^1],les,de-1,x);
        return query(ch[now][bit],les,de-1,x);
    }
    void work()
    {
        int x=read(),y=read(),z=read(),lca=LCA(x,y);
        printf("%d\n",max(query(root[x],dep[lca],30,z),query(root[y],dep[lca],30,z)));
    }
}
int main()
{
    n=read(),Q=read();
    rep(i,1,n) scanf("%d",poi+i);
    for(int u,v,i=1;i<n;i++)
        u=read(),v=read(),add(u,v),add(v,u);
    work1::init();
    work2::init();
    rep(i,1,Q)
    {
        if(read()==1) work1::work();
        else work2::work();
    }
    return 0;
}

2018.11.3