[ICPC2020南京J] Just Another Game of Stones - 线段树
Description
给定一串石子堆 (b_{i}),有如下两种操作:
将区间 ([l,r]) 中的石子堆中的石子数量变为 (max(b_{i}, x))。
取出区间 ([l,r]) 中的石子堆,新增第 (r-l+2) 个石子堆,其中石子数量为 (x)。询问有多少种方法拿石子使得转变为必胜态。
Solution
对这个 Nim 游戏的条件稍作变形,能转化为求区间内多少个数指定位是 1
Segment tree beats, 区间最值操作需要维护:区间最小值、区间次小值、区间最小值个数
对于修改值夹在最小和次小之间的情况直接刷掉最小值,而同时大于等于最小和次小的则递归处理
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n, q;
unsigned hight_bit(unsigned x)
{ //0010 1100 0000 0000 0000 0000 0000 0000 0000 0001
x = x | (x >> 1); //0011 1110 0000 0000 0000 0000 0000 0000 0000 0000
x = x | (x >> 2); //0011 1111 1000 0000 0000 0000 0000 0000 0000 0000
x = x | (x >> 4); //0011 1111 1111 1000 0000 0000 0000 0000 0000 0000
x = x | (x >> 8); //0011 1111 1111 1111 1111 1000 0000 0000 0000 0000
x = x | (x >> 16); //0011 1111 1111 1111 1111 1111 1111 1111 1111 1111
return (x + 1) >> 1; //0100 0000 0000 0000 0000 0000 0000 0000 0000 0000
}
int ffs(int x)
{
return __builtin_ffs(hight_bit(x));
}
struct Node
{
int min_value, submin_value, min_count, sum[30];
Node()
{
min_value = 1e18;
submin_value = 1e18;
min_count = 0;
for (int i = 0; i < 30; i++)
sum[i] = 0;
}
Node operator+(const Node &rhs)
{
Node res;
for (int i = 0; i < 30; i++)
res.sum[i] = sum[i] + rhs.sum[i];
res.min_value = min(min_value, rhs.min_value);
res.submin_value = min(submin_value, rhs.submin_value);
res.min_count = 0;
if (min_value != rhs.min_value)
res.submin_value = min(res.submin_value, max(min_value, rhs.min_value));
if (res.min_value == min_value)
res.min_count += min_count;
if (res.min_value == rhs.min_value)
res.min_count += rhs.min_count;
return res;
}
void Set(int x)
{
min_value = x;
submin_value = 1e18;
min_count = 1;
for (int i = 0; i < 30; i++)
if (x & (1 << i))
sum[i] = 1;
else
sum[i] = 0;
}
int xor_sum()
{
int ans = 0;
for (int i = 0; i < 30; i++)
if (sum[i] & 1)
ans += 1 << i;
return ans;
}
int getans()
{
int hb = ffs(xor_sum());
return hb ? sum[hb - 1] : 0;
}
} nodes[1000005];
void pushup(int p)
{
nodes[p] = nodes[p * 2] + nodes[p * 2 + 1];
}
void put(int p, int x)
{
if (x <= nodes[p].min_value)
return;
int tmp = nodes[p].min_value;
for (int i = 0; i < 30; i++)
if (tmp & (1 << i))
nodes[p].sum[i] -= nodes[p].min_count;
nodes[p].min_value = tmp = x;
for (int i = 0; i < 30; i++)
if (tmp & (1 << i))
nodes[p].sum[i] += nodes[p].min_count;
}
void pushdown(int p)
{
put(p * 2, nodes[p].min_value);
put(p * 2 + 1, nodes[p].min_value);
}
void build(int p, int l, int r, const vector<int> &src)
{
if (l == r)
{
nodes[p].Set(src[l]);
}
else
{
build(p * 2, l, (l + r) / 2, src);
build(p * 2 + 1, (l + r) / 2 + 1, r, src);
pushup(p);
}
}
void modify(int p, int l, int r, int ql, int qr, int x)
{
if (l > qr || r < ql || x <= nodes[p].min_value)
return;
if (l >= ql && r <= qr && x <= nodes[p].submin_value)
put(p, x);
else
{
pushdown(p);
modify(p * 2, l, (l + r) / 2, ql, qr, x);
modify(p * 2 + 1, (l + r) / 2 + 1, r, ql, qr, x);
pushup(p);
}
}
Node query(int p, int l, int r, int ql, int qr)
{
if (l > qr || r < ql)
return Node();
if (l >= ql && r <= qr)
return nodes[p];
pushdown(p);
return query(p * 2, l, (l + r) / 2, ql, qr) + query(p * 2 + 1, (l + r) / 2 + 1, r, ql, qr);
}
signed main()
{
ios::sync_with_stdio(false);
cin >> n >> q;
vector<int> a(n + 2);
for (int i = 1; i <= n; i++)
cin >> a[i];
build(1, 1, n, a);
for (int i = 1; i <= q; i++)
{
int op, l, r, x;
cin >> op >> l >> r >> x;
if (op == 1)
{
modify(1, 1, n, l, r, x);
}
else
{
Node node;
node.Set(x);
auto tmp = query(1, 1, n, l, r);
auto res = query(1, 1, n, l, r) + node;
cout << (query(1, 1, n, l, r) + node).getans() << endl;
}
}
}