题面:给定长度为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<=1000,m<=300000)
思路:因为n比较小,所以维护第二维,然后暴力询问第一维。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=1010,maxm=300010,maxt=10000010; int n,m,x[maxn],y[maxm],q,a,b,c,d,k; struct Tree{ struct node{int size,son[2];}t[maxt]; int tot,root[maxm],a[maxm],t1[maxn],t2[maxn]; int newnode(){return ++tot;} void insert(int id,int val){ root[id]=newnode();t[root[id]].size=t[root[id-1]].size+1; int now=root[id],pre=root[id-1]; for (int j=31,v;j>=0;j--){ v=(val>>j)&1;t[now].son[v]=newnode(); t[t[now].son[v]].size=t[t[pre].son[v]].size+1; t[now].son[v^1]=t[pre].son[v^1]; now=t[now].son[v],pre=t[pre].son[v]; } } void query(int u,int d,int l,int r,int rank){ for (int i=u;i<=d;i++) t1[i]=root[l-1],t2[i]=root[r]; int res=0; for (int k=31;k>=0;k--){ int sum=0; for (int i=u;i<=d;i++){ int v=(x[i]>>k)&1; sum+=t[t[t2[i]].son[v^1]].size-t[t[t1[i]].son[v^1]].size; } if (rank<=sum){ for (int i=u;i<=d;i++){ int v=(x[i]>>k)&1; t1[i]=t[t1[i]].son[v^1],t2[i]=t[t2[i]].son[v^1]; } res|=(1<<k); } else{ for (int i=u;i<=d;i++){ int v=(x[i]>>k)&1; t1[i]=t[t1[i]].son[v],t2[i]=t[t2[i]].son[v]; } rank-=sum; } } printf("%d\n",res); } }Trie; int main(){ scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%d",&x[i]); for (int i=1;i<=m;i++) scanf("%d",&y[i]); for (int i=1;i<=m;i++) Trie.insert(i,y[i]); for (scanf("%d",&q);q;q--) scanf("%d%d%d%d%d",&a,&b,&c,&d,&k),Trie.query(a,b,c,d,k); return 0; }