【BZOJ 4103】[Thu Summer Camp 2015]異或運算 可持久化trie樹

矩陣什麼的不用管,就是a給一個區間,b給一個區間兩兩異或第k大,發現b很大a很小,就給b建一個可持久化trie樹,順便記下size以便於查詢第k大。

對於每一次的詢問,外層枚舉位數,內層枚舉A的每一個數,用結構體存下每一個A中的數對應的B的可持久化trie樹的當前節點,然後分別就像查詢一個數一樣樹上二分就好了。

#include<cstdio>
#include<cstring>
#include<iostream>
#define maxm 300021
#define ls(u) ch[u][0]
#define rs(u) ch[u][1]
using namespace std;
int n,m,a[1021],tot,rt[maxm],ch[maxm*40][2];
int size[maxm*40];
struct node{
	int x,y,val;
}q[maxm];
void insert(int x,int& y,int val){
	y=++tot;int root=y;size[y]=size[x]+1;
	for(int c,i=31;i>=0;i--){
		c=(val>>i)&1;
		ch[root][!c]=ch[x][!c];
		root=ch[root][c]=++tot;
		x=ch[x][c];
		size[root]=size[x]+1;
	}
}
int query(int cnt,int k){
	int sz=0,ans=0;
	for(int i=31;i>=0;i--){
		sz=0;
		for(int c,j=1;j<=cnt;j++){
			c=(q[j].val>>i)&1;
			sz+=size[ch[q[j].y][!c]]-size[ch[q[j].x][!c]];
		}
		if(sz>=k){
			ans=ans<<1|1;
			for(int j=1,c;j<=cnt;j++){
				c=(q[j].val>>i)&1;
				q[j].x=ch[q[j].x][!c],
				q[j].y=ch[q[j].y][!c];
			}
		}else{
			k-=sz;ans=ans<<1;
			for(int j=1,c;j<=cnt;j++){
				c=(q[j].val>>i)&1;
				q[j].x=ch[q[j].x][c],
				q[j].y=ch[q[j].y][c];
			}
		}
	}
	return ans;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%d",a+i);
	for(int x,i=1;i<=m;i++){
		scanf("%d",&x);
		insert(rt[i-1],rt[i],x);
	}
	int Q;int u,d,l,r,k,cnt;
	scanf("%d",&Q);
	while(Q--){
		cnt=0;
		scanf("%d%d%d%d%d",&u,&d,&l,&r,&k);
		for(int i=u;i<=d;i++)q[++cnt]=(node){rt[l-1],rt[r],a[i]};
		printf("%d\n",query(cnt,k));
	}
	return 0;
}


發佈了339 篇原創文章 · 獲贊 18 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章