洛谷P4735题解

若想要深入学习可持久化0-1Trie树,传送门


Description:

给定数列 \(\{a_n\}\) ,支持两种操作:

  • 在数列尾添加一个数 \(x\) ,数列长度变成 \(n+1\) ;
  • 给定闭区间 \([l,r]\) 和一个数 \(x\) ,求:

\[\max_{i=l}^{r}\left \{\left(\bigoplus_{j=i}^{n}a_j \right)\bigoplus x\right \} \]

Method:

定义 \(Xorsum_i\)\(\bigoplus_{i=1}^{n}a_i\) ,即前缀异或和。我们显然可以得到

\[\left(\bigoplus_{i=pos}^{n}a_i\right)\bigoplus x=Xorsum_{pos-1}\bigoplus Xorsum_n \bigoplus x \]

\(x\bigoplus x=0\) , \(x \bigoplus 0=x\)

我们发现 \(Xorsum_n\bigoplus x\) 是一个定值,我们只需要维护 \(Xorsum_{pos-1}\) 即可。

考虑用可持久化0-1Trie树维护。与主席树思路相同 ,我们建立 \(n+1\) 个版本的0-1Trie树,查询的时候运用贪心的思路即可。

可持久化线段树同样支持“前缀和”的思想,我们最后只需要在第 \(r\) 个版本的0-1Trie树上查找 \(l\) 位置即可。

本题毒瘤卡常,本人人丑常数大,用了fread等各种卡常操作才通过。并且由于luogu评测姬的原因(大雾,已经通过的代码又会T掉woc。卡不过的话,开o2吧。

Code:

#include<bits/stdc++.h>
#define Maxn 600010
#define Maxdep 23
#define getchar()(p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[1<<21],*p1=buf,*p2=buf;
inline void read(int &x)
{
    int f=1;x=0;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    x*=f;
}
int n,m;
int sum[Maxn];
struct trie
{
    trie *chd[2];
    int symbl;
    trie()
    {
        for(int i=0;i<2;i++) chd[i]=NULL;
        symbl=0;
    }
}*root[Maxn],tree[Maxn<<5],*tail;
void Init(){tail=tree;} 
void build(trie *&p,int dep)
{
    p=new (tail++)trie();
    if(dep<0) return ;
    build(p->chd[0],dep-1);
}
void update(trie *&p,trie *flag,int dep,int i)
{
    p=new (tail++)trie();
    if(flag) *p=*flag;
    if(dep<0) return (void)(p->symbl=i);
    int tmp=(sum[i]>>dep)&1;//判断是1还是0 
    if(!tmp) update(p->chd[0],flag?flag->chd[0]:NULL,dep-1,i);
    else update(p->chd[1],flag?flag->chd[1]:NULL,dep-1,i);
    if(p->chd[0]) p->symbl=std::max(p->symbl,p->chd[0]->symbl);
    if(p->chd[1]) p->symbl=std::max(p->symbl,p->chd[1]->symbl);
}
int query(trie *p,int x,int dep,int limit)
{
    if(dep<0) return sum[p->symbl]^x;
    int tmp=(x>>dep)&1;
    if(p->chd[tmp^1]&&p->chd[tmp^1]->symbl>=limit) return query(p->chd[tmp^1],x,dep-1,limit);
    return query(p->chd[tmp],x,dep-1,limit);
}
signed main()
{
    Init();
    read(n),read(m);
    build(root[0],Maxdep);
    for(int i=1,x;i<=n;i++)
    {
        read(x);
        sum[i]=sum[i-1]^x;
        update(root[i],root[i-1],Maxdep,i);
    } 
    for(int i=1;i<=m;i++)
    {
        char ch=getchar();
        while(ch!='A'&&ch!='Q') ch=getchar();
        if(ch=='A')
        {
            int x;
            read(x);
            n++;
            sum[n]=sum[n-1]^x;
            update(root[n],root[n-1],Maxdep,n);	
            continue;
        }	
        if(ch=='Q')
        {
            int l,r,x;
            read(l),read(r),read(x);
            int ans=query(root[r-1],sum[n]^x,Maxdep,l-1);
            printf("%d\n",ans);
            continue;
        }
    }
    return 0;
}
posted @ 2019-11-03 02:25  nth_element  阅读(251)  评论(0编辑  收藏  举报