[BZOJ4103][Thu Summer Camp 2015]异或运算 可持久化Trie树
4103: [Thu Summer Camp 2015]异或运算
Time Limit: 20 Sec Memory Limit: 512 MBDescription
给定长度为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.
题解:
看到“区间”“k小”几个关键词,我们自然想到了可持久化数据结构
再加上“异或”,那么可持久化Trie没跑了。
我们发现这个数据范围极不平衡……
所以我们考虑对于M建立Trie树,这样for循环扫起来数据比较小,最多只需要同时扫2000棵Trie即可
这样我们把n里面所有点,以及对应区间的Trie都存进vector或者其他容器里面,然后处理即可。和主席树非常相似。
代码见下:
1 #include <cstdio> 2 #include <cstring> 3 #include <vector> 4 using namespace std; 5 typedef long long LL; 6 const int M=300100,N=1010; 7 int a,b,c,d,k,n,m,x[N];LL bin[40]; 8 struct Trie 9 { 10 int size;Trie *ch[2]; 11 Trie(){size=0;ch[0]=ch[1]=NULL;} 12 }*null=new Trie(),*root[M]; 13 vector<Trie*>v[5]; 14 vector<int>vec; 15 inline Trie* newTrie(){Trie *o=new Trie();o->ch[0]=o->ch[1]=null;return o;} 16 void insert(Trie *&o,Trie *old,int val,int i) 17 { 18 if(i<0)return; 19 int d=((val&bin[i])==bin[i]); 20 o->ch[d]=newTrie();o->ch[d^1]=old->ch[d^1]; 21 o->ch[d]->size=old->ch[d]->size+1; 22 insert(o->ch[d],old->ch[d],val,i-1); 23 } 24 inline int query() 25 { 26 v[1].clear(),v[2].clear();vec.clear(); 27 for(int i=a;i<=b;i++) 28 vec.push_back(x[i]),v[1].push_back(root[c-1]),v[2].push_back(root[d]); 29 int ret=0; 30 for(int i=30;~i;i--) 31 { 32 int tmp=0; 33 for(int j=0,len=v[1].size();j<len;j++) 34 { 35 int d=((vec[j]&bin[i])==bin[i]); 36 tmp+=v[2][j]->ch[d^1]->size-v[1][j]->ch[d^1]->size; 37 } 38 if(tmp>=k) 39 { 40 ret|=bin[i]; 41 for(int j=0,len=v[1].size();j<len;j++) 42 { 43 int d=((vec[j]&bin[i])==bin[i]); 44 v[1][j]=v[1][j]->ch[d^1],v[2][j]=v[2][j]->ch[d^1]; 45 } 46 } 47 else 48 { 49 k-=tmp; 50 for(int j=0,len=v[1].size();j<len;j++) 51 { 52 int d=((vec[j]&bin[i])==bin[i]); 53 v[1][j]=v[1][j]->ch[d],v[2][j]=v[2][j]->ch[d]; 54 } 55 } 56 } 57 return ret; 58 } 59 int main() 60 { 61 int q;scanf("%d%d",&n,&m); 62 bin[0]=1;for(int i=1;i<=35;i++)bin[i]=bin[i-1]<<1; 63 root[0]=newTrie();null->ch[0]=null->ch[1]=null; 64 for(int i=1;i<=n;i++)scanf("%d",&x[i]); 65 for(int i=1;i<=m;i++) 66 root[i]=newTrie(),scanf("%d",&a),insert(root[i],root[i-1],a,30); 67 scanf("%d",&q); 68 while(q--) 69 scanf("%d%d%d%d%d",&a,&b,&c,&d,&k),printf("%d\n",query()); 70 }
Progress is not created by contented people.