BZOJ4103 [Thu Summer Camp 2015]异或运算 【可持久化trie树】

题目链接

BZOJ4103

题解

一眼看过去是二维结构,实则未然需要树套树之类的数据结构
区域异或和,就一定是可持久化\(trie\)

观察数据,\(m\)非常大,而\(n\)\(p\)比较小,甚至可以每次询问都枚举\(x_i\)
所以我们可以考虑对\(y_i\)\(trie\),每次询问取出对应区间的\(x_i\)在对应区间的\(trie\)树中跑

多点询问和单点询问时类似的,只不过它们会分开走
我们只需每次记录每个\(x_i\)所在的节点
对于每一层,统计一下能异或出多少\(1\),如果\(\le k\),每个\(x_i\)往能异或出\(1\)的方向走,否则走另一边,并令\(k\)减去这些数

复杂度\(O(31m + 31qn)\)

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define mp(a,b) make_pair<int,int>(a,b)
#define cls(s) memset(s,0,sizeof(s))
#define cp pair<int,int>
#define LL long long int
using namespace std;
const int maxn = 300005,B = 30,maxm = 10000005,INF = 1000000000;
inline int read(){
	int out = 0,flag = 1; char c = getchar();
	while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
	while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
	return out * flag;
}
int bin[50],n,m;
int a[1005],b[maxn],rt[maxn],cnt;
int ch[maxm][2],sum[maxm];
int ins(int x,int v){
	int u,tmp;
	u = tmp = ++cnt;
	for (int i = B; ~i; i--){
		ch[u][0] = ch[v][0];
		ch[u][1] = ch[v][1];
		sum[u] = sum[v] + 1;
		int t = bin[i] & x; t >>= i;
		v = ch[v][t];
		u = ch[u][t] = ++cnt;
	}
	sum[u] = sum[v] + 1;
	return tmp;
}
int atu[1005],atv[1005];
int query(int u,int v,int l,int r,int k){
	int ans = 0;
	for (int i = l; i <= r; i++) atu[i] = u,atv[i] = v;
	for (int i = B; ~i; i--){
		int cnt = 0;
		for (int j = l; j <= r; j++){
			int x = atu[j],y = atv[j],t = bin[i] & a[j]; t >>= i;
			cnt += sum[ch[x][t ^ 1]] - sum[ch[y][t ^ 1]];
		}
		if (cnt >= k){
			ans += bin[i];
			for (int j = l; j <= r; j++){
				int x = atu[j],y = atv[j],t = bin[i] & a[j]; t >>= i;
				atu[j] = ch[x][t ^ 1];
				atv[j] = ch[y][t ^ 1];
			}			
		}
		else {
			k -= cnt;
			for (int j = l; j <= r; j++){
				int x = atu[j],y = atv[j],t = bin[i] & a[j]; t >>= i;
				atu[j] = ch[x][t];
				atv[j] = ch[y][t];
			}
		}
	}
	return ans;
}
int main(){
	bin[0] = 1; for (int i = 1; i <= 30; i++) bin[i] = bin[i - 1] << 1;
	n = read(); m = read();
	for (int i = 1; i <= n; i++) a[i] = read();
	for (int i = 1; i <= m; i++){
		b[i] = read();
		rt[i] = ins(b[i],rt[i - 1]);
	}
	int p = read(),u,d,l,r,k;
	while (p--){
		u = read(); d = read(); l = read(); r = read(); k = read();
		printf("%d\n",query(rt[r],rt[l - 1],u,d,k));
	}
	return 0;
}

posted @ 2018-05-24 20:11  Mychael  阅读(155)  评论(0编辑  收藏  举报