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
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
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
题解:
注意到p,u,d都很小,所以可以对第二维建可持久化trie,然后枚举第一维.
查询的时候在可持久化trie上跑一遍即可.
注意查询的时候对需要每个数记录一下当前它在trie树上的位置.
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 300010
using namespace std;
int bin[35],ch[N*32][2],sum[N*32],root[N],n,m,l,r,k,u,d,num,cnt,Q,a[N],b[N];
struct use{int x,y,v;}q[N];
int insert(int x,int v){
int t,y;t=y=++cnt;
for (int i=30;i>=0;i--){
int t=v&bin[i];t>>=i;
ch[y][0]=ch[x][0];ch[y][1]=ch[x][1];
y=ch[y][t]=++cnt;
x=ch[x][t];sum[y]=sum[x]+1;
}
return t;
}
int query(int k){
int ans(0);
for (int i=30;i>=0;i--){
int size(0);
for (int j=1;j<=num;j++){
int t=(q[j].v)&bin[i];t>>=i;
size+=sum[ch[q[j].y][t^1]]-sum[ch[q[j].x][t^1]];
}
if (size>=k){
ans+=bin[i];
for (int j=1;j<=num;j++){
int t=(q[j].v)&bin[i];t>>=i;
q[j].x=ch[q[j].x][t^1];q[j].y=ch[q[j].y][t^1];
}
}
else{
k-=size;
for (int j=1;j<=num;j++){
int t=(q[j].v)&bin[i];t>>=i;
q[j].x=ch[q[j].x][t];q[j].y=ch[q[j].y][t];
}
}
}
return ans;
}
int main(){
scanf("%d%d",&n,&m);
bin[0]=1;for (int i=1;i<=30;i++) bin[i]=bin[i-1]*2;
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (int i=1;i<=m;i++) scanf("%d",&b[i]),root[i]=insert(root[i-1],b[i]);
scanf("%d",&Q);
for (int i=1;i<=Q;i++){
scanf("%d%d%d%d%d",&u,&d,&l,&r,&k);num=0;
for (int j=u;j<=d;j++) q[++num]=use{root[l-1],root[r],a[j]};
printf("%d\n",query(k));
}
}
本文介绍了一种解决特定矩阵查询问题的方法,利用二维可持久化Trie树来高效地找出给定矩阵区域内的第k大元素。适用于数据规模较小的情况,通过枚举和查询操作实现快速响应。
831

被折叠的 条评论
为什么被折叠?



