矩陣什麼的不用管,就是a給一個區間,b給一個區間兩兩異或第k大,發現b很大a很小,就給b建一個可持久化trie樹,順便記下size以便於查詢第k大。
對於每一次的詢問,外層枚舉位數,內層枚舉A的每一個數,用結構體存下每一個A中的數對應的B的可持久化trie樹的當前節點,然後分別就像查詢一個數一樣樹上二分就好了。
#include<cstdio>
#include<cstring>
#include<iostream>
#define maxm 300021
#define ls(u) ch[u][0]
#define rs(u) ch[u][1]
using namespace std;
int n,m,a[1021],tot,rt[maxm],ch[maxm*40][2];
int size[maxm*40];
struct node{
int x,y,val;
}q[maxm];
void insert(int x,int& y,int val){
y=++tot;int root=y;size[y]=size[x]+1;
for(int c,i=31;i>=0;i--){
c=(val>>i)&1;
ch[root][!c]=ch[x][!c];
root=ch[root][c]=++tot;
x=ch[x][c];
size[root]=size[x]+1;
}
}
int query(int cnt,int k){
int sz=0,ans=0;
for(int i=31;i>=0;i--){
sz=0;
for(int c,j=1;j<=cnt;j++){
c=(q[j].val>>i)&1;
sz+=size[ch[q[j].y][!c]]-size[ch[q[j].x][!c]];
}
if(sz>=k){
ans=ans<<1|1;
for(int j=1,c;j<=cnt;j++){
c=(q[j].val>>i)&1;
q[j].x=ch[q[j].x][!c],
q[j].y=ch[q[j].y][!c];
}
}else{
k-=sz;ans=ans<<1;
for(int j=1,c;j<=cnt;j++){
c=(q[j].val>>i)&1;
q[j].x=ch[q[j].x][c],
q[j].y=ch[q[j].y][c];
}
}
}
return ans;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",a+i);
for(int x,i=1;i<=m;i++){
scanf("%d",&x);
insert(rt[i-1],rt[i],x);
}
int Q;int u,d,l,r,k,cnt;
scanf("%d",&Q);
while(Q--){
cnt=0;
scanf("%d%d%d%d%d",&u,&d,&l,&r,&k);
for(int i=u;i<=d;i++)q[++cnt]=(node){rt[l-1],rt[r],a[i]};
printf("%d\n",query(cnt,k));
}
return 0;
}