Description
给定长度为n的数列X={x1,x2,…,xn}和长度为m的数列Y={y1,y2,…,ym},令矩阵A中第i行第j列的值Aij=xi xor yj,每次询问给定矩形区域i∈[u,d],j∈[l,r],找出第k大的Aij。
Input
第一行包含两个正整数n,m,分别表示两个数列的长度
第二行包含n个非负整数xi
第三行包含m个非负整数yj
第四行包含一个正整数p,表示询问次数
随后p行,每行均包含5个正整数,用来描述一次询问,每行包含五个正整数u,d,l,r,k,含义如题意所述。
Output
共p行,每行包含一个非负整数,表示此次询问的答案。
Sample Input
3 3
1 2 4
7 6 5
3
1 2 1 2 2
1 2 1 3 4
2 3 2 3 4
Sample Output
6
5
1
HINT
对于100%的数据,0<=Xi,Yj<2^31,
1<=u<=d<=n<=1000,
1<=l<=r<=m<=300000,
1<=k<=(d-u+1)*(r-l+1),
1<=p<=500
解题思路:
注意n很小,明显是来暴力的。
将y数组建出可持久化trie树,从高位开始贪心,记录a[u]~a[d]在trie树上的位置即可。
时间复杂度 O(pnlogm) O ( p n l o g m )
#include<bits/stdc++.h>
#define ll long long
#define pb push_back
using namespace std;
int getint()
{
ll i=0,f=1;char c;
for(c=getchar();(c!='-')&&(c<'0'||c>'9');c=getchar());
if(c=='-')c=getchar(),f=-1;
for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
const int N=300005;
int n,m,tot,a[1005],lpo[1005],rpo[1005],rt[N];
struct node{int son[2],cnt;}tr[N*35];
void insert(int y,int &x,int i,int v)
{
tr[x=++tot]=tr[y];tr[x].cnt++;
if(i==-1)return;
int t=v>>i&1;
insert(tr[y].son[t],tr[x].son[t],i-1,v);
}
int query(int l,int r,int x,int y,int k)
{
for(int i=l;i<=r;i++)lpo[i]=x,rpo[i]=y;
int res=0;
for(int i=30;i>=0;i--)
{
int cnt=0;
for(int j=l;j<=r;j++)
{
int t=a[j]>>i&1;
cnt+=tr[tr[rpo[j]].son[t^1]].cnt-tr[tr[lpo[j]].son[t^1]].cnt;
}
if(k<=cnt)
{
res|=1<<i;
for(int j=l;j<=r;j++)
{
int t=a[j]>>i&1;
lpo[j]=tr[lpo[j]].son[t^1],rpo[j]=tr[rpo[j]].son[t^1];
}
}
else
{
k-=cnt;
for(int j=l;j<=r;j++)
{
int t=a[j]>>i&1;
lpo[j]=tr[lpo[j]].son[t],rpo[j]=tr[rpo[j]].son[t];
}
}
}
return res;
}
int main()
{
//freopen("lx.in","r",stdin);
n=getint(),m=getint();
for(int i=1;i<=n;i++)a[i]=getint();
for(int i=1;i<=m;i++)insert(rt[i-1],rt[i],30,getint());
for(int Q=getint(),u,d,l,r,k;Q;Q--)
{
u=getint(),d=getint(),l=getint(),r=getint(),k=getint();
printf("%d\n",query(u,d,rt[l-1],rt[r],k));
}
return 0;
}