洛谷 P7906 [Ynoi2005] rpxleqxq

洛谷传送门

考虑莫队二次离线。剩下是平衡插入和查询复杂度的问题。

考虑现在的问题:要求 \(O(\sqrt{n})\) 往集合里插入一个数,\(O(1)\) 回答集合内有多少个数 \(x\) 满足 \(z \oplus x \le m\)\(z\) 给定)。

考虑高低位分块。先钦定 \(z\) 在前 \(9\) 位时 \(z \oplus x < m\),枚举 \(z\) 的前 \(9\) 位更新答案;然后钦定 \(z\)\(9\)\(= m \oplus x\),枚举 \(z\) 的后 \(9\) 位更新答案。查询是 \(O(1)\) 的。

总时间复杂度 \(O(n + (\sqrt{n} + \sqrt{q}))\)

code
// Problem: P7906 [Ynoi2005] rpxleqxq
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P7906
// Memory Limit: 128 MB
// Time Limit: 1500 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 200100;
const int maxm = 1000100;

int n, m, q, a[maxn], blo, bel[maxn];
ll ans[maxm], b[maxn];

struct node {
	int l, r, i;
	ll ans;
} qq[maxm];

namespace DS {
	int f[555], g[555][555];
	
	inline void init() {
		mems(f, 0);
		mems(g, 0);
	}
	
	inline void insert(int x) {
		for (int i = 0; i < 512; ++i) {
			f[i] += (((x >> 9) ^ i) < (m >> 9));
		}
		int t = (x ^ m) >> 9;
		for (int i = 0; i < 512; ++i) {
			g[t][i] += (((x & 511) ^ i) <= (m & 511));
		}
	}
	
	inline int query(int x) {
		return f[x >> 9] + g[(x >> 9) & 511][x & 511];
	}
}

struct line {
	int l, r, i, o;
	line(int a = 0, int b = 0, int c = 0, int d = 0) : l(a), r(b), i(c), o(d) {}
};
vector<line> vc[maxn];

void solve() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; ++i) {
		scanf("%d", &a[i]);
	}
	scanf("%d", &q);
	for (int i = 1; i <= q; ++i) {
		scanf("%d%d", &qq[i].l, &qq[i].r);
		qq[i].i = i;
	}
	blo = ceil(n / sqrt(q));
	for (int i = 1; i <= n; ++i) {
		bel[i] = (i - 1) / blo + 1;
	}
	sort(qq + 1, qq + q + 1, [&](const node &a, const node &b) {
		if (bel[a.l] != bel[b.l]) {
			return bel[a.l] < bel[b.l];
		} else if (bel[a.l] & 1) {
			return a.r < b.r;
		} else {
			return a.r > b.r;
		}
	});
	for (int i = 1; i <= n; ++i) {
		b[i] = b[i - 1] + DS::query(a[i]);
		DS::insert(a[i]);
	}
	int l = 1, r = 0;
	for (int i = 1; i <= q; ++i) {
		int L = qq[i].l, R = qq[i].r;
		if (l > L) {
			qq[i].ans -= b[l - 1] - b[L - 1] + l - L;
			vc[r].pb(L, l - 1, i, 1);
			l = L;
		}
		if (r < R) {
			qq[i].ans += b[R] - b[r];
			vc[l - 1].pb(r + 1, R, i, -1);
			r = R;
		}
		if (l < L) {
			qq[i].ans += b[L - 1] - b[l - 1] + L - l;
			vc[r].pb(l, L - 1, i, -1);
			l = L;
		}
		if (r > R) {
			qq[i].ans -= b[r] - b[R];
			vc[l - 1].pb(R + 1, r, i, 1);
			r = R;
		}
	}
	DS::init();
	for (int i = 1; i <= n; ++i) {
		DS::insert(a[i]);
		for (line u : vc[i]) {
			for (int j = u.l; j <= u.r; ++j) {
				qq[u.i].ans += u.o * DS::query(a[j]);
			}
		}
	}
	for (int i = 1; i <= q; ++i) {
		qq[i].ans += qq[i - 1].ans;
		ans[qq[i].i] = qq[i].ans;
	}
	for (int i = 1; i <= q; ++i) {
		printf("%lld\n", ans[i]);
	}
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

posted @ 2024-01-26 22:43  zltzlt  阅读(39)  评论(0)    收藏  举报