BZOJ 4103: [Thu Summer Camp 2015]异或运算 可持久化trie
开始想了一个二分+可持久化trie验证,比正解多一个 log
仔细思考,你发现你可以直接按位枚举,然后在可持久化 trie 上二分就好了.
code:
#include <bits/stdc++.h> #define N 700005 #define setIO(s) freopen(s".in","r",stdin) using namespace std; int n,m,tot,tl,tr; int ch[N*30][2],cnt[N*30],xx[N],yy[N],rt[N],t1[N],t2[N]; void insert(int pre,int &x,int v) { int now=x=++tot; for(int i=30;i>=0;--i) { int o=((v>>i)&1); ch[now][o^1]=ch[pre][o^1]; ch[now][o]=++tot; pre=ch[pre][o]; now=ch[now][o]; cnt[now]=cnt[pre]+1; } } int query(int L,int R,int kth,int len) { if(len<0) return 0; int re=0,cur=1,i; for(cur=1,i=L;i<=R;++i,++cur) { int o=((xx[i]>>len)&1); re+=cnt[ch[t2[cur]][o^1]]-cnt[ch[t1[cur]][o^1]]; } if(kth<=re) { for(cur=1,i=L;i<=R;++i,++cur) { int o=((xx[i]>>len)&1); t1[cur]=ch[t1[cur]][o^1]; t2[cur]=ch[t2[cur]][o^1]; } return (1<<len)+query(L,R,kth,len-1); } else { for(cur=1,i=L;i<=R;++i,++cur) { int o=((xx[i]>>len)&1); t1[cur]=ch[t1[cur]][o]; t2[cur]=ch[t2[cur]][o]; } return query(L,R,kth-re,len-1); } } int main() { // setIO("input"); int i,j; scanf("%d%d",&n,&m); for(i=1;i<=n;++i) scanf("%d",&xx[i]); for(i=1;i<=m;++i) { scanf("%d",&yy[i]); insert(rt[i-1],rt[i],yy[i]); } int q; scanf("%d",&q); while(q--) { int a,b,c,d,k; scanf("%d%d%d%d%d",&a,&b,&c,&d,&k); tl=tr=0; for(i=a;i<=b;++i) t1[++tl]=rt[c-1],t2[tl]=rt[d]; printf("%d\n",query(a,b,k,30)); } return 0; }