zoukankan      html  css  js  c++  java
  • ICPC 2020 南京站J Just Another Game of Stones

    题意

    给出(n)堆石子,数量分别是(a_1 - a_n),有两种操作:

    • 修改操作,给出(l, r, x),对(a[l cdots r])(x)进行区间取( ext{max}操作),即(a_i = max(a_i, x))

    • 查询操作,给出(l, r, x),将(a[l cdots r])与数量为(x)的一堆石子一共(r - l + 2)堆石子拿出来玩nim游戏,问先手获胜的方法有几种

    做法

    大型缝合怪题。

    场上yy了一个神奇的线段树套01Tire的做法,我自己都觉得写不出来。

    先用nim游戏的结论,求出(a[l cdots r])(x)的异或和(s),如果(s = 0)是先手必败,否则就是询问区间中有多少个数(包括(x))满足(a_i igotimes s leqslant s)

    这个东西稍微推一下就可以发现,是询问区间中(s)的最高位为(1)的数有多少个,证明很简单。

    然后看到区间取max的操作,应该是一个segment beats,发现只要维护区间每一位为1的数的数量,套上板子,可以维护。

    其实,这个题到这里应该就做完了,因为通过枚举位数可以知道区间的异或和,然后我就偷懒少维护了一个异或和,然后T成sb。

    
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef double db;
    typedef pair <int, int> pin;
    
    const int N = 2e5 + 5;
    const int M = 30;
    const ll P = 998244353LL;
    const int inf = 1 << 30;
    
    int n, qn, a[N];
    
    namespace Fread {
        const int L = 1 << 15;
        
        char buffer[L], *S, *T;
        
        inline char Getchar() {
            if(S == T) {
                T = (S = buffer) + fread(buffer, 1, L, stdin);
                if(S == T) return EOF;
            }
            return *S++;
        }
        
        template <class T> 
        inline void read(T &X) {
            char ch; T op = 1;
            for(ch = Getchar(); ch > '9' || ch < '0'; ch = Getchar())
                if(ch == '-') op = -1;
            for(X = 0; ch >= '0' && ch <= '9'; ch = Getchar()) 
                X = (X << 1) + (X << 3) + ch - '0'; 
            X *= op;
        }
        
    } using Fread::read;   
    
    namespace Fwrite {
        const int L = 1 << 15;
        
        char buf[L], *pp = buf;
        
        void Putchar(const char c) {
            if(pp - buf == L) fwrite(buf, 1, L, stdout), pp = buf;
            *pp++ = c;
        }
        
        template<typename T>
        void print(T x) {
            if(x < 0) {
                Putchar('-');
                x = -x;
            }
            if(x > 9) print(x / 10);
            Putchar(x % 10 + '0');
        }
        
        void fsh() {
            fwrite(buf, 1, pp - buf, stdout);
            pp = buf;
        }
        
        template <typename T>
        inline void write(T x, char ch = 0) {
            print(x);
            if (ch != 0) Putchar(ch);
            fsh();
        }
    
    } using Fwrite::write;
    
    namespace SegT {
        int mn[N << 2], sec[N << 2], mnCnt[N << 2], cnt[M][N << 2], tag[N << 2], sum[N << 2];
    
        #define lc (p << 1)
        #define rc (p << 1 | 1)
        #define mid ((l + r) >> 1)
    
        inline void up(int p) {
            sum[p] = sum[lc] ^ sum[rc];
            for (int i = 0; i < 30; i++) cnt[i][p] = cnt[i][lc] + cnt[i][rc];
            if (mn[lc] < mn[rc]) {
                mn[p] = mn[lc];
                mnCnt[p] = mnCnt[lc];
                sec[p] = min(sec[lc], mn[rc]);
            } else if (mn[lc] == mn[rc]) {
                mn[p] = mn[lc];
                mnCnt[p] = mnCnt[lc] + mnCnt[rc];
                sec[p] = min(sec[lc], sec[rc]);
            } else {
                mn[p] = mn[rc];
                mnCnt[p] = mnCnt[rc];
                sec[p] = min(sec[rc], mn[lc]);
            }
        }
    
        inline void down(int p) {
            if (tag[p] > mn[lc] && tag[p] < sec[lc]) {
                for (int i = 0; i < 30; i++) {
                    int now = 1 << i;
                    if (now > mn[lc] && now > tag[p]) break;
                    if (mn[lc] & now) cnt[i][lc] -= mnCnt[lc];
                    if (tag[p] & now) cnt[i][lc] += mnCnt[lc];
                }
                if (mnCnt[lc] & 1) sum[lc] ^= mn[lc] ^ tag[p];
                mn[lc] = tag[p];
                tag[lc] = tag[p];
            }
            if (tag[p] > mn[rc] && tag[p] < sec[rc]) {
                for (int i = 0; i < 30; i++) {
                    int now = 1 << i;
                    if (now > mn[rc] && now > tag[p]) break;
                    if (mn[rc] & now) cnt[i][rc] -= mnCnt[rc];
                    if (tag[p] & now) cnt[i][rc] += mnCnt[rc];
                }
                if (mnCnt[rc] & 1) sum[rc] ^= mn[rc] ^ tag[p];
                mn[rc] = tag[p];
                tag[rc] = tag[p];
            }
        }
    
        void build(int p, int l, int r) {
            if (l == r) {
                tag[p] = mn[p] = sum[p] = a[l];
                for (int i = 0; i < 30; i++)
                    if (a[l] & (1 << i)) ++cnt[i][p];
                sec[p] = inf;
                mnCnt[p] = 1;
                return;
            }
            build(lc, l, mid), build(rc, mid + 1, r);
            up(p);
        }
    
        void getMax(int p, int l, int r, int x, int y, int v) {
            if (x <= l && y >= r) {
                if (v <= mn[p]) return;
                else if (v > mn[p] && v < sec[p]) {
                    for (int i = 0; i < 30; i++) {
                        int now = 1 << i;
                        if (now > mn[p] && now > v) break;
                        if (mn[p] & now) cnt[i][p] -= mnCnt[p];
                        if (v & now) cnt[i][p] += mnCnt[p];
                    }
                    if (mnCnt[p] & 1) sum[p] ^= mn[p] ^ v;
                    mn[p] = tag[p] = v;
                } else {
                    down(p);
                    getMax(lc, l, mid, x, y, v), getMax(rc, mid + 1, r, x, y, v);
                    up(p);
                }
                return;
            }
            down(p);
            if (x <= mid) getMax(lc, l, mid, x, y, v);
            if (y > mid) getMax(rc, mid + 1, r, x, y, v);
            up(p);
        }
    
        int qBit(int p, int l, int r, int x, int y, int w) {
            if (x <= l && y >= r) return cnt[w][p];
            down(p);
            int res = 0;
            if (x <= mid) res += qBit(lc, l, mid, x, y, w);
            if (y > mid) res += qBit(rc, mid + 1, r, x, y, w);
            return res;
        }
    
        int qSum(int p, int l, int r, int x, int y) {
            if (x <= l && y >= r) return sum[p];
            down(p);
            int res = 0;
            if (x <= mid) res ^= qSum(lc, l, mid, x, y);
            if (y > mid) res ^= qSum(rc, mid + 1, r, x, y);
            return res;
        }
    
    } using namespace SegT;
    
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("sample.in", "r", stdin);
        clock_t st_clock = clock();
    #endif
    
        read(n), read(qn);
        for (int i = 1; i <= n; i++) read(a[i]);
        build(1, 1, n);
        for (int opt, x, y, v; qn--; ) {
            read(opt), read(x), read(y), read(v);
            if (opt == 1) {
                getMax(1, 1, n, x, y, v);
            } else {
                // int s = 0;
                // for (int bin = 1, i = 0; i < 30; i++, bin <<= 1) {
                //     int now = qBit(1, 1, n, x, y, i);
                //     if (now & 1) s += bin;
                // }
                int s = qSum(1, 1, n, x, y);
                s ^= v;
                if (s == 0) write(0, '
    ');
                else {
                    int w = 0;
                    for (int tmp = s; tmp != 0; tmp >>= 1, ++w);
                    --w;
                    int res = qBit(1, 1, n, x, y, w);
                    if ((v ^ s) <= v) ++res;
                    write(res, '
    ');
                }
            }
    
            // for (int i = 1; i <= n; i++) {
            //     int now = 0;
            //     for (int j = 0; j < 30; j++) now += qBit(1, 1, n, i, i, j) << j;
            //     printf("%d%c", now, " 
    "[i == n]);
            // }
        }
    
    #ifndef ONLINE_JUDGE
        clock_t ed_clock = clock();
        printf("time = %f ms
    ", (double)(ed_clock - st_clock) / CLOCKS_PER_SEC * 1000);
    #endif
        return 0;
    }
    

    链接

    segment beats 冬令营课件

    UOJ的一个讨论帖,jls关于复杂度的声明

    CF 上的一篇介绍文,下有题目

  • 相关阅读:
    jQuery-遍历
    jQuery-尺寸方法
    jQuery-操作css类
    jQuery-添加/删除元素
    jQuery捕获-获取DOM元素内容和属性
    Props属性
    jQuery事件
    jQuery选择器
    JQ基本选择器
    注册事件
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/14425984.html
Copyright © 2011-2022 走看看