1. 程式人生 > >洛谷 P4735 最大異或和 解題報告

洛谷 P4735 最大異或和 解題報告

P4735 最大異或和

題目描述

給定一個非負整數序列\(\{a\}\),初始長度為\(N\)

\(M\)個操作,有以下兩種操作型別:

  1. A x:新增操作,表示在序列末尾新增一個數\(x\),序列的長度\(N+1\)
  2. Q l r x:詢問操作,你需要找到一個位置\(p\),滿足\(l \le p \le r\),使得: \(a[p] \oplus a[p+1] \oplus \cdots \oplus a[N] \oplus x\)最大,輸出最大是多少。

輸入輸出格式

輸入格式:

第一行包含兩個整數 \(N,M\),含義如問題描述所示。
第二行包含 \(N\)個非負整數,表示初始的序列\(A\)


接下來\(M\)行,每行描述一個操作,格式如題面所述。

輸出格式:

假設詢問操作有 \(T\) 個,則輸出應該有 \(T\) 行,每行一個整數表示詢問的答案。

說明

對於測試點 \(1-2\)\(N,M \le 5\)
對於測試點 \(3-7\)\(N,M \le 80000\)
對於測試點 \(8-10\)\(N,M \le 300000\)
其中測試點 \(1, 3, 5, 7, 9\)保證沒有修改操作。
\(0 \le a[i] \le 10^7\)


不知道為什麼覺得這玩意兒挺可愛。

可持久化字典樹,思想上和可持久化的所有東西都差不多,每次加入修改的一部分副本,剩下的用之前的。

大致流程是,和前一個點一起帶進去,安排自己的兒子,然後把前一個點的兒子拿過來用。

對於這個題目,由異或的性質可以等價於求

\(s[p] \oplus s[n] \oplus x\)的最大值,其中\(s[i]\)表示異或字首和,然後後面兩個是一個可以得到的值,我們只需要在一個區間的數中找到一個數與它異或起來最大就可以了。

如果我們可以在那個區間的字典樹上找相反的點,就可以得到最大值了。

於是把可持久化字典樹建出來,查詢\(r-1\)之前的字典樹,為了不查到\(l-1\)之前的,對字典樹每個節點維護一下這棵子樹的編號最大的末尾節點。


Code:

#include <cstdio>
#include <cctype>
const int N=6e5+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 n,m,s[N],mx[N*24],ch[N*24][2],root[N],tot;char op[3];
int max(int x,int y){return x>y?x:y;}
#define ls ch[now][0]
#define rs ch[now][1]
void Insert(int las,int &now,int dep,int id)
{
    if(!now) now=++tot;
    if(!(~dep)) {mx[now]=id;return;}
    Insert(ch[las][s[id]>>dep&1],ch[now][s[id]>>dep&1],dep-1,id);
    if(!ls)ls=ch[las][0];if(!rs)rs=ch[las][1];
    mx[now]=max(mx[ls],mx[rs]);
}
int query(int now,int les,int x,int dep)
{
    if(!(~dep)) return x^s[mx[now]];
    int bit=x>>dep&1;
    if(mx[ch[now][bit^1]]>=les)
        return query(ch[now][bit^1],les,x,dep-1);
    else
        return query(ch[now][bit],les,x,dep-1);
}
#define rep(i,a,b) for(int i=a;i<=b;i++)
int main()
{
    scanf("%d%d",&n,&m);
    mx[0]=-1;
    Insert(0,root[0],23,0);
    rep(i,1,n)
        s[i]=s[i-1]^read(),Insert(root[i-1],root[i],23,i);
    rep(i,1,m)
    {
        scanf("%s",op);
        if(op[0]=='A')
        {
            ++n,s[n]=s[n-1]^read();
            Insert(root[n-1],root[n],23,n);
        }
        else
        {
            int l=read(),r=read();
            printf("%d\n",query(root[r-1],l-1,s[n]^read(),23));
        }
    }
    return 0;
}

2018.11.2