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;
}