给定长度为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。
给定长度为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。
第一行包含两个正整数n,m,分别表示两个数列的长度
共p行,每行包含一个非负整数,表示此次询问的答案。
对于100%的数据,0<=Xi,Yj<2^31,
鸣谢佚名上传
可持久化Trie树
发现n和m的范围差距很大,所以n可以暴力枚举,m用可持久化Trie树提取区间。
题目要求a数组一段区间的数和b数组一段区间的数异或的k大值,考虑从高位到低位贪心,每次尽量选1,否则选0。
于是从高到低枚举每一位,询问a数组每一个元素对应那棵Trie树上节点大小,进而判断这一位能否填1。
注意:a数组每一个数对应的Trie树要分别保存。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #define F(i,j,n) for(int i=j;i<=n;i++) #define D(i,j,n) for(int i=j;i>=n;i--) #define ll long long #define N 1005 #define M 300005 using namespace std; int n,m,q,cnt,x_1,x_2,y_1,y_2,k; int a[N],b[M]; int sz[M*35],c[M*35][2],rt[M]; struct data{int x,y;}p[N]; inline int read() { int x=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } void insert(int x,int &y,int val,int tmp) { y=++cnt;sz[y]=sz[x]+1; c[y][0]=c[x][0];c[y][1]=c[x][1]; if (tmp==-1) return; int t=(val>>tmp)&1; insert(c[x][t],c[y][t],val,tmp-1); } int solve(int k,int tmp) { if (tmp==-1) return 0; int sum=0; F(i,x_1,x_2) { int t=(a[i]>>tmp)&1; sum+=sz[c[p[i].y][t^1]]-sz[c[p[i].x][t^1]]; } if (sum>=k) { F(i,x_1,x_2) { int t=(a[i]>>tmp)&1; p[i].x=c[p[i].x][t^1]; p[i].y=c[p[i].y][t^1]; } return solve(k,tmp-1)+(1<<tmp); } else { F(i,x_1,x_2) { int t=(a[i]>>tmp)&1; p[i].x=c[p[i].x][t]; p[i].y=c[p[i].y][t]; } return solve(k-sum,tmp-1); } } int main() { n=read();m=read(); F(i,1,n) a[i]=read(); F(i,1,m) b[i]=read(); F(i,1,m) insert(rt[i-1],rt[i],b[i],30); q=read(); while (q--) { x_1=read();x_2=read();y_1=read();y_2=read();k=read(); F(i,x_1,x_2) p[i].x=rt[y_1-1],p[i].y=rt[y_2]; printf("%d\n",solve(k,30)); } }