[LOJ#517]. 「LibreOJ β Round #2」计算几何瞎暴力[trie]

题意

题目链接

分析

  • 记操作异或和为 \(tx\) ,最后一次排序时的异或和为 \(ax\) ,每个数插入时的 \(tx\) 记为 \(b\)

  • 我们发现,一旦数列排序,就会变得容易操作。

  • 对于新加入的数字用一个前缀和数组维护每一位为 1 的个数(每个数保证在 \(xor​\) 当前 \(tx​\) 之后能够得到真实结果)。对于进行过排序的数字用 trie 维护(每个数用 \(a_i\ xor\ b_i​\) 表示)。

  • 查找 trie 上的数字在 \(xor\ ax\) 排序后的前 \(k\) 个值中每一位有多少个1,如果 \(ax\) 对应位是 1 就先走右子树。

  • 如果要进行新的排序,就将没插入 trie 的数字以 \(a_i\ xor\ b_i\) 插入到 trie 中即可。

  • 时间复杂度 \(O(nlogn)\)

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define go(u) for(int i = head[u], v = e[i].to; i; i=e[i].lst, v=e[i].to)
#define rep(i, a, b) for(int i = a; i <= b; ++i)
#define pb push_back
#define re(x) memset(x, 0, sizeof x)
inline int gi() {
    int x = 0,f = 1;
    char ch = getchar();
    while(!isdigit(ch)) { if(ch == '-') f = -1; ch = getchar();}
    while(isdigit(ch)) { x = (x << 3) + (x << 1) + ch - 48; ch = getchar();}
    return x * f;
}
template <typename T> inline bool Max(T &a, T b){return a < b ? a = b, 1 : 0;}
template <typename T> inline bool Min(T &a, T b){return a > b ? a = b, 1 : 0;}
const int N = 2e5 + 7;
int n, tp, m;
int a[N], num[N];
int ax, totx;
int f[N][33], res[33];
namespace Trie {
	const int Nd = N * 33;
	int ch[Nd][2], ndc = 1, son[Nd], sum[Nd][33];
	void insert(int x) {
		int u = 1;
		for(int i = 30; ~i; --i) {
			rep(j, 0, i + 1) if(x >> j & 1) ++sum[u][j];
			++son[u];
			int c = x >> i & 1;
			if(!ch[u][c]) ch[u][c] = ++ndc;
			u = ch[u][c];
		}
		if(x & 1)
			++sum[u][0];
		++son[u];
	}
	void query(int u, int i, int k) {
		if(!u || !k || i < 0) return;
		int c = ax >> i & 1;
		if(son[ch[u][c]] >= k) query(ch[u][c], i - 1, k), res[i] += c * k;
		else {
			rep(j, 0, i) res[j] += sum[ch[u][c]][j];
			query(ch[u][c ^ 1], i - 1, k - son[ch[u][c]]);
			res[i] += (c ^ 1) * (k - son[ch[u][c]]);
		}
	}
	LL query(int l, int r) {
		LL ans = 0;
		re(res);
		query(1, 30, r);
		rep(j, 0, 30)
		ans += 1ll * (totx >> j & 1 ? r - res[j] : res[j]) << j;
		
		re(res);
		query(1, 30, l - 1);
		rep(j, 0, 30)
		ans -= 1ll * (totx >> j & 1 ? l - 1 - res[j] : res[j]) << j;
		return ans;
	}
}

LL query(int l, int r) {
	LL ans = 0;
	memcpy(res, f[r], sizeof res);
	rep(j, 0, 30)
	ans += 1ll * (totx >> j & 1 ? r - res[j] : res[j]) << j;
	memcpy(res, f[l - 1], sizeof res);
	rep(j, 0, 30)
	ans -= 1ll * (totx >> j & 1 ? l - 1 - res[j] : res[j]) << j;
	return ans;
}
int main() {
	n = gi();
	rep(i, 1, n) {
		int x = gi();
		num[++tp] = x;
		rep(j, 0, 30) f[tp][j] = f[tp - 1][j] + (x >> j & 1);
	}
	m = gi();
	while(m--) {
		int opt = gi();
		if(opt == 1) {
			int x = gi();
			num[++tp] = x ^ totx;
			rep(j, 0, 30) f[tp][j] = f[tp - 1][j] + ((x ^ totx) >> j & 1);
		}
		if(opt == 2) {
			int l = gi(), r = gi(), k = Trie::son[1];
			if(r <= k)
				printf("%lld\n", Trie::query(l, r));
			else if(l <= k) 
				printf("%lld\n", query(1, r - k) + Trie::query(l, k));
			else 
				printf("%lld\n", query(l - k, r - k));
		}
		if(opt == 3) {
			totx ^= gi();
		}
		if(opt == 4) {
			for(; tp; --tp) Trie::insert(num[tp]);
			ax = totx;
		}
	}
	return 0;
}
posted @ 2019-03-18 10:35  fwat  阅读(192)  评论(0编辑  收藏  举报