【BZOJ4103】[Thu Summer Camp 2015]异或运算
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和p很小,考虑暴力枚举行。我们将n个x值都拿出来,对于y维护可持久化Trie树,然后将这些x一起放到可持久化Trie树上二分即可。集体做法与主席树的求第k大类似。
#include <cstdio> #include <cstring> #include <iostream> using namespace std; int n,m,tot,Q; struct node { int ch[2],siz; }s[10000010]; int v[1010],p[1010],p1[1010],p2[1010],rt[300010]; inline int rd() { int ret=0,f=1; char gc=getchar(); while(gc<‘0‘||gc>‘9‘) {if(gc==‘-‘) f=-f; gc=getchar();} while(gc>=‘0‘&&gc<=‘9‘) ret=ret*10+gc-‘0‘,gc=getchar(); return ret*f; } int insert(int x,int val) { int u,tmp=++tot,d,i; for(u=tmp,i=1<<30;i;i>>=1) { d=(val&i)>0,s[u].ch[d]=++tot,s[u].ch[d^1]=s[x].ch[d^1]; u=s[u].ch[d],x=s[x].ch[d],s[u].siz=s[x].siz+1; } return tmp; } int query(int len,int k) { int i,j,ret=0,d,dd,sum; for(i=1<<30;i;i>>=1) { for(sum=0,j=1;j<=len;j++) { d=!(p[j]&i); sum+=s[s[p2[j]].ch[d]].siz-s[s[p1[j]].ch[d]].siz; } if(sum>=k) dd=0,ret|=i; else dd=1,k-=sum; for(j=1;j<=len;j++) { d=(!(p[j]&i))^dd; p2[j]=s[p2[j]].ch[d],p1[j]=s[p1[j]].ch[d]; } } return ret; } int main() { n=rd(),m=rd(); int i,j,a,b,c,d; for(i=1;i<=n;i++) v[i]=rd(); for(i=1;i<=m;i++) rt[i]=insert(rt[i-1],rd()); Q=rd(); for(i=1;i<=Q;i++) { a=rd(),b=rd(),c=rd(),d=rd(); for(j=a;j<=b;j++) p[j-a+1]=v[j],p1[j-a+1]=rt[c-1],p2[j-a+1]=rt[d]; printf("%d\n",query(b-a+1,rd())); } return 0; }//3 3 1 2 4 7 6 5 3 1 2 1 2 2 1 2 1 3 4 2 3 2 3 4
时间: 2024-10-21 08:47:57