zoukankan      html  css  js  c++  java
  • [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";
        }
    }
    
  • 相关阅读:
    将博客搬至CSDN
    IDEA安装对应版本的lombok才生效
    shift键复选dataGrid的记录时多余的文本总被选择了。
    git 导出新修改的文件
    svn老鸟转用git必须理解的概念
    java中Long类型和long类型的大小比较
    eclipse反编译插件jadClipse安装使用教程
    js闭包
    java泛型讲解
    常用加密解密算法【RSA、AES、DES、MD5】介绍和使用
  • 原文地址:https://www.cnblogs.com/mollnn/p/14661052.html
Copyright © 2011-2022 走看看