01-Trie

概述

以前也不是没写过 \(\mathbf{01-Tire}\) 的博客,只是单纯觉得写的太复杂了而已.现在也不打算些什么,写一些小 \(\mathbf{trick}\) 或记录一些有意思的题目好了.以前那篇博客在这里:Link. 密码是喜闻乐见的机房密码(有人问有没有空格这里统一回答一下没有).

出于怕被爬本来打算锁的,后来想想还是算了.还可以督促自己不要咕咕咕.jpg

P5283 [十二省联考 2019] 异或粽子

题目链接:Link.

题意转化过来就是要你选出 \(k\) 段区间 \([l,r]\) ,每段区间的权值是这段区间内的数的异或和,求一种选法使所有区间的总权值最大.不允许选相同的区间.输出那个最大值.

区间异或不难想到前缀和.求出前缀异或和这个题就变成了让你求 \(k\) 个无序点对使得这个些点对的异或和最大.考虑无序不太好做,直接按有序做最后答案除以 \(2\) 即可.问题变成了如何求所有点对.考虑对所有点建 \(\mathbf{01-Tire}\) ,依次求出对于所有点异或和最大的点,次大的点...把所有求出来的值丢到一个优先队列里,每次取队头即可.这样可以保证每一次取出的一定是所有情况中第一大的,第二大的...第 \(2k\) 大的.

讲不太清,看代码应该很容易.已经尽量只保留了代码里比较重要的部分了.

struct Trie{
    inline ll qry(ll x,ll rk){
        ll rt=0,as=0;
        for(register int i=31;i>=0;--i){
            ll c=(x>>i)&1;
            if(!tr[rt][c^1]) rt=tr[rt][c];
            else if(rk<=sz[tr[rt][c^1]]) as|=(1LL<<i),rt=tr[rt][c^1];
            else rk-=sz[tr[rt][c^1]],rt=tr[rt][c];
        }
        return as;
    }
}tr;

struct node{
    ll id,rk,w;
    inline bool operator <(const node &a)const{return w<a.w;}
};


int main(){
    n=read();k=read();k<<=1;
    for(register int i=1;i<=n;++i) x=read(),a[i]=a[i-1]^x;
    for(register int i=0;i<=n;++i) tr.ins(a[i]);
    for(register int i=0;i<=n;++i) q.push((node){i,1,tr.qry(a[i],1)});
    for(register int i=1;i<=k;++i){
        node nw=q.top();q.pop();
        ans+=nw.w;
        if(nw.rk<n) q.push((node){nw.id,nw.rk+1,tr.qry(a[nw.id],nw.rk+1)});
    }
    printf("%lld\n",(ans>>1));
    return 0;
}

P4735 最大异或和

题目链接:Link.

很好的可持久化 \(\mathbf{01-Trie}\) 模板题.由于异或的可减性,不妨设异或前缀和为 \(s\) ,显然有 \(a_p \oplus a_{p+1} \oplus ... a_n \oplus x=s_{p-1}\oplus s_n \oplus x\) .于是相当于对于 \(s_n \oplus x\) ,在所有的 \([l-1,r-1]\) 中找到一个 \(p\) ,使得 \(s_p\oplus s_n \oplus x\) 最大.

直接跑即可,具体细节可以看看代码,和主席树思路很像.

一个很小的细节是需要特判区间是 \([0,r-1]\) 的情况.本质上 \(rt_0\) 是为 \(rt_1\) 服务的,相当于插入了一个 \(0\) .但实际是不存在这个 \(0\) 的,跑询问的时候自然也不应该牵扯进去.

struct Trie{

    ll cnt=0;
    ll ch[maxn*30][2];
    ll sz[maxn*30];

    inline void ins(ll id,ll o,ll nw,ll vl){
        if(nw<0) return;
        ll c=(vl>>nw)&1;
        ch[id][c^1]=ch[o][c^1];
        ch[id][c]=++cnt;
        sz[ch[id][c]]=sz[ch[o][c]]+1;
        ins(ch[id][c],ch[o][c],nw-1,vl);
    }

    inline ll qry(ll id,ll o,ll nw,ll vl){
        if(nw<0) return 0;
        ll c=(vl>>nw)&1;
        if(sz[ch[o][c^1]]>sz[ch[id][c^1]]) return (1<<nw)+qry(ch[id][c^1],ch[o][c^1],nw-1,vl);
        else return qry(ch[id][c],ch[o][c],nw-1,vl);
    }

}tr;

int main(){
    n=read(),m=read();
    rt[0]=++tr.cnt;
    tr.ins(rt[0],0,25,0);
    for(register int i=1;i<=n;++i){
        ll x=read();a[i]=a[i-1]^x;
        rt[i]=++tr.cnt,tr.ins(rt[i],rt[i-1],25,a[i]);
    }
    for(register int i=1;i<=m;++i){
        cin>>s;
        if(s[0]=='A'){
            ll x=read();++n,a[n]=a[n-1]^x;
            rt[n]=++tr.cnt,tr.ins(rt[n],rt[n-1],25,a[n]);
        }
        else{
            L=read(),R=read(),u=read();--L,--R;
            if(!L) printf("%d\n",tr.qry(0,rt[R],25,u^a[n]));
            else printf("%d\n",tr.qry(rt[L-1],rt[R],25,u^a[n]));
        }
    }
    return 0;
}
posted @ 2022-03-09 16:30  XeniaF  阅读(27)  评论(0编辑  收藏  举报