[ICPC2020南京J] Just Another Game of Stones

[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;
        }
    }
}
原文地址:https://www.cnblogs.com/mollnn/p/14587025.html