BZOJ 4103: [Thu Summer Camp 2015]异或运算

第一次打可持久化trie树。。不过貌似不是太难打?
M很大 对M个数来建可持久化trie树 N较小 在询问的时候一起搞就好
不难得出复杂度 O(m32+nq32)

异或这种东西 不难就能想到用trie树 然后统计一下数量 搞一下 求第K大
比如让它尽量大的话 这一位是0就走去1 是1的话就反之

自认为代码还是挺好看的~(为什么我又觉得他有点慢)

#include<bits/stdc++.h>
using namespace std;
const int N=1002,M=300002,D=30;
inline int read(){
    char ch=getchar(); int x=0,f=1;
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0'; ch=getchar();}
    return x*f;
}
int a[N],rt[M],tot,lc[M*32],rc[M*32],c[M*32];
void add(int id,int x){
    rt[id]=++tot; int y=rt[id-1],nw=tot;
    for(int i=D;~i;i--){
        int u=x>>i; x&=(1<<i)-1;
        if(u){
            rc[nw]=++tot,c[tot]=c[rc[y]]+1;
            lc[nw]=lc[y],nw=tot,y=rc[y];
        }
        else{
            lc[nw]=++tot,c[tot]=c[lc[y]]+1;
            rc[nw]=rc[y],nw=tot,y=lc[y];
        }
    }
}
int nl[N],nr[N],L,R,l,r,k;
void query(){
    int ret=0,i;
    for(i=L;i<=R;i++)nl[i]=rt[l-1],nr[i]=rt[r];
    for(i=D;~i;i--){
        int x=0;
        for(int j=L;j<=R;j++){
            int u=(a[j]>>i)&1;
            if(u)x+=c[lc[nr[j]]]-c[lc[nl[j]]];
            else x+=c[rc[nr[j]]]-c[rc[nl[j]]];
        }
        if(x>=k){
            for(int j=L;j<=R;j++){
                int u=(a[j]>>i)&1;
                if(u)nr[j]=lc[nr[j]],nl[j]=lc[nl[j]];
                else nr[j]=rc[nr[j]],nl[j]=rc[nl[j]];
            }
            ret|=(1<<i);
        }
        else{
            k-=x;
            for(int j=L;j<=R;j++){
                int u=(a[j]>>i)&1;
                if(u)nr[j]=rc[nr[j]],nl[j]=rc[nl[j]];
                else nr[j]=lc[nr[j]],nl[j]=lc[nl[j]];
            }
        }
    }
    printf("%d\n",ret);
}
int main()
{
    int n=read(),m=read(),i,x;
    for(i=1;i<=n;i++)a[i]=read();
    for(i=1;i<=m;i++){
        x=read(); add(i,x);
    }
    int q=read();
    while(q--){
        L=read(),R=read(),l=read(),r=read(),k=read();
        query();
    }
    return 0;
}

你可能感兴趣的:(BZOJ 4103: [Thu Summer Camp 2015]异或运算)