开始想了一个二分+可持久化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;
}

  

01-08 16:34