[CF1511G] Chips on a Board

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