P9631 [ICPC2020 Nanjing R] Just Another Game of Stones 题解
tribool4_in · · 题解
吉司机线段树。
操作为区间修改取
考虑询问如何实现。考虑 Nim 游戏的结论:令
考虑如何得出可操作方案数。不妨把
考虑异或的性质。对于
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int n, q, a[N];
struct node {
int mn, se, mncnt, tag;
int xors, cnt[30];
} t[N << 2];
void push_up(int p) {
t[p].xors = t[p << 1].xors ^ t[p << 1 | 1].xors;
for (int i = 0; i < 30; i++) t[p].cnt[i] = t[p << 1].cnt[i] + t[p << 1 | 1].cnt[i];
if (t[p << 1].mn == t[p << 1 | 1].mn) {
t[p].mn = t[p << 1].mn, t[p].mncnt = t[p << 1].mncnt + t[p << 1 | 1].mncnt;
t[p].se = min(t[p << 1].se, t[p << 1 | 1].se);
} else if (t[p << 1].mn < t[p << 1 | 1].mn) {
t[p].mn = t[p << 1].mn, t[p].mncnt = t[p << 1].mncnt;
t[p].se = min(t[p << 1].se, t[p << 1 | 1].mn);
} else if (t[p << 1].mn > t[p << 1 | 1].mn) {
t[p].mn = t[p << 1 | 1].mn, t[p].mncnt = t[p << 1 | 1].mncnt;
t[p].se = min(t[p << 1].mn, t[p << 1 | 1].se);
}
}
void build(int p, int l, int r) {
t[p].tag = -1;
if (l == r) {
t[p].mn = t[p].xors = a[l], t[p].se = INT_MAX, t[p].mncnt = 1;
for (int i = 0; i < 30; i++) t[p].cnt[i] = (a[l] >> i & 1);
return;
}
int mid = (l + r) >> 1;
build(p << 1, l, mid), build(p << 1 | 1, mid + 1, r);
push_up(p);
}
void set_tag(int p, int v) {
if (t[p].mn >= v) return;
t[p].xors ^= ((t[p].mncnt & 1) * (t[p].mn ^ v));
for (int i = 0; i < 30; i++)
t[p].cnt[i] += ((v >> i & 1) - (t[p].mn >> i & 1)) * t[p].mncnt;
t[p].mn = t[p].tag = v;
}
void push_down(int p) {
if (t[p].tag == -1) return;
set_tag(p << 1, t[p].tag), set_tag(p << 1 | 1, t[p].tag);
t[p].tag = -1;
}
void update(int p, int l, int r, int x, int y, int v) {
if (t[p].mn >= v) return;
if (x <= l && r <= y && v < t[p].se) {
set_tag(p, v);
return;
}
push_down(p);
int mid = (l + r) >> 1;
if (x <= mid) update(p << 1, l, mid, x, y, v);
if (mid < y) update(p << 1 | 1, mid + 1, r, x, y, v);
push_up(p);
}
int query1(int p, int l, int r, int x, int y) {
if (x <= l && r <= y) return t[p].xors;
push_down(p);
int mid = (l + r) >> 1, res = 0;
if (x <= mid) res ^= query1(p << 1, l, mid, x, y);
if (mid < y) res ^= query1(p << 1 | 1, mid + 1, r, x, y);
return res;
}
int query2(int p, int l, int r, int x, int y, int k) {
if (x <= l && r <= y) return t[p].cnt[k];
push_down(p);
int mid = (l + r) >> 1, res = 0;
if (x <= mid) res += query2(p << 1, l, mid, x, y, k);
if (mid < y) res += query2(p << 1 | 1, mid + 1, r, x, y, k);
return res;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n >> q;
for (int i = 1; i <= n; i++) cin >> a[i];
build(1, 1, n);
for (int i = 1, op, l, r, x; i <= q; i++) {
cin >> op >> l >> r >> x;
if (op == 1) {
update(1, 1, n, l, r, x);
} else {
int y = query1(1, 1, n, l, r) ^ x, b = -1;
for (int j = 0; j < 30; j++)
if (y >> j & 1) b = j;
if (b == -1) {
cout << "0\n";
continue;
}
int ans = query2(1, 1, n, l, r, b) + (x >> b & 1);
cout << ans << '\n';
}
}
return 0;
}