[CF1511G] Chips on a Board - 主席树,拆位
Description
……
Solution
对所有 (c_i) 升序排序,这样问题就转化为了对于一个升序序列,每次给定 (l,r,x),求 (oplus_{i=l}^r (a_i-x)) 是否等于零
要判定一个数是否等于零,只需要判定它的每一位是否等于零,也就是要判断所有 ([l,r]) 间有多少个 (i) 满足 (a_i-x) 的第 (b) 位是 (1)
对于第 (b) 位,我们只需要知道,有多少个 (a_i) 满足 (a_i in [x+2^{b-1},x+2^b-1] mod 2^b)
考虑对于每一位,分别建立一棵长为 (2^b) 的主席树来维护 (a_i mod 2^b) 的每种值的出现次数,用版本做差来解决区间约束,时间复杂度 (O(nlog^2 n))
#include <bits/stdc++.h>
using namespace std;
const int N = 4e5 + 5;
const int M = 4.1e7 + 5;
const int B = 19;
// todo: chairman tree
int ch[M][2], val[M], ind, root[B][N];
void modify(int &p, int q, int l, int r, int pos)
{
p = ++ind;
ch[p][0] = ch[q][0];
ch[p][1] = ch[q][1];
val[p] = val[q];
val[p]++;
if (l == r)
return;
if (pos <= (l + r) / 2)
modify(ch[p][0], ch[q][0], l, (l + r) / 2, pos);
else
modify(ch[p][1], ch[q][1], (l + r) / 2 + 1, r, pos);
}
int query(int p, int l, int r, int ql, int qr)
{
if (p == 0)
return 0;
if (l > qr || r < ql)
return 0;
if (l >= ql && r <= qr)
return val[p];
return query(ch[p][0], l, (l + r) / 2, ql, qr) + query(ch[p][1], (l + r) / 2 + 1, r, ql, qr);
}
int range_query(int p, int q, int l, int r, int ql, int qr)
{
return query(q, l, r, ql, qr) - query(p, l, r, ql, qr);
}
// todo: main
int n, m, c[N], q;
signed main()
{
ios::sync_with_stdio(false);
cin >> n >> m;
memset(ch, 0, sizeof ch);
memset(val, 0, sizeof val);
memset(root, 0, sizeof root);
for (int i = 1; i <= n; i++)
cin >> c[i];
sort(c + 1, c + n + 1);
for (int b = 1; b < B; b++)
{
int pw2 = 1 << b;
int pw1 = 1 << (b - 1);
root[b][0] = ++ind;
for (int i = 1; i <= n; i++)
{
modify(root[b][i], root[b][i - 1], 0, pw2 - 1, c[i] % pw2);
}
}
cin >> q;
for (int i = 1; i <= q; i++)
{
int L, R;
cin >> L >> R;
int l = lower_bound(c + 1, c + n + 1, L) - c;
int r = upper_bound(c + 1, c + n + 1, R) - c - 1;
int x = L;
int flag = 0;
for (int b = 1; b < B; b++)
{
int pw2 = 1 << b;
int pw1 = 1 << (b - 1);
int lb = (x + pw1) % pw2;
int rb = (x + pw2 - 1) % pw2;
int res = 0;
if (lb <= rb)
res += range_query(root[b][l - 1], root[b][r], 0, pw2 - 1, lb, rb);
else
{
res += r - l + 1 - range_query(root[b][l - 1], root[b][r], 0, pw2 - 1, rb + 1, lb - 1);
}
if (res & 1)
{
flag = 1;
break;
}
}
if (flag)
cout << "A";
else
cout << "B";
}
}