• Luogu P4883 mzf的考验


    题目传送门

    早已离我远去的六一儿童节……


    维护区间翻转,很容易可以想到用(Splay)来维护

    唯一的难点就是如何维护操作(2)
    因为异或是对于每一个二进制位上的操作,而(d leq 2 ^ {20}),所以对于节点(x),我们可以开一个数组a[i],表示(x)和它的子树中第(i)个二进制位上的(1)的总和

    题目比较卡常,需要开(o2)优化

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define ls tree[p].s[0]
    #define rs tree[p].s[1]
    #define LL long long
    using namespace std;
    LL read() {
        LL k = 0; char c = getchar();
        while(c < '0' || c > '9') c = getchar();
        while(c >= '0' && c <= '9')
            k = k * 10 + c - 48, c= getchar();
        return k;
    }
    int root, tot;
    struct zzz {
        int s[2], num, fa;
        LL a[25], val, sum, tag2;
        bool tag;
    }tree[100010];
    void up(int p) {
        tree[p].sum = tree[ls].sum + tree[rs].sum + tree[p].val;
        tree[p].num = tree[ls].num + tree[rs].num + 1;
        for(int i = 0; i <= 20; ++i)
            tree[p].a[i] = tree[ls].a[i] + tree[rs].a[i] + ((tree[p].val >> i) & 1);
    }
    void Xor(int p, LL x) {
        LL k = 0;
        for(int i = 0; i <= 20; ++i) {
            if((x >> i) & 1) tree[p].a[i] = tree[p].num - tree[p].a[i];
            k += 1ll * (1 << i) * tree[p].a[i];
        }
        //cout << k << endl;
        tree[p].tag2 ^= x; tree[p].val ^= x; tree[p].sum = k;
    }
    void rev(int p) {
        if(!p) return ;
        tree[p].tag ^= 1;
        swap(ls, rs);
    }
    void down(int p) {
        if(tree[p].tag) {
            rev(ls), rev(rs);
            tree[p].tag = 0;
        }
        if(tree[p].tag2) {
            Xor(ls, tree[p].tag2);
            Xor(rs, tree[p].tag2);
            tree[p].tag2 = 0;
        }
    }
    void rotate(int p) {
        int f = tree[p].fa;
        int ff = tree[f].fa;
        bool k = tree[f].s[1] == p;
    
        tree[ff].s[tree[ff].s[1] == f] = p;
        tree[p].fa = ff;
    
        tree[f].s[k] = tree[p].s[k ^ 1];
        tree[tree[p].s[k ^ 1]].fa = f;
    
        tree[p].s[k ^ 1] = f;
        tree[f].fa = p;
    
        up(f), up(p);
    }
    void Splay(int p, int goal) {
        while(tree[p].fa != goal) {
            int f = tree[p].fa;
            int ff = tree[f].fa;
            if(ff != goal)
                (tree[f].s[0] == p) ^ (tree[ff].s[0] == f) ? rotate(p) : rotate(f);
            rotate(p);
        }
        if(goal == 0) root = p;
    }
    LL a[100010];
    void build(int &p, int l, int r) {
        if(l > r) return ;
        int mid = (l + r) >> 1;
        p = mid;
        tree[p].val = a[p];
        build(ls, l, mid-1), build(rs, mid+1, r);
        if(ls) tree[ls].fa = p; if(rs) tree[rs].fa = p;
        up(p);
    }
    int k_th(int x) {
        int p = root;
        if(tree[p].num < x) return false;
        while(p) {
            down(p);
            if(x > tree[ls].num + 1)
                x -= tree[ls].num + 1, p = rs;
            else if(tree[ls].num >= x) p = ls;
            else return p;
        }
        return p;
    }
    int main() {
        int n = read(), m = read();
        for(int i = 1; i <= n; ++i) a[i+1] = read();
        build(root, 1, n+2);
        while(m--) {
            int opt = read(), l = read(), r = read();
            l = k_th(l); r = k_th(r+2);
            Splay(l, 0); Splay(r, root);
            if(opt == 1) {
                rev(tree[tree[root].s[1]].s[0]);
            }
            else if(opt == 2) {
                Xor(tree[tree[root].s[1]].s[0], read());
            }
            else if(opt == 3) {
                printf("%lld
    ", tree[tree[tree[root].s[1]].s[0]].sum);
            }
        }
    
    
        return 0;
    }
    

    弱化版题目CF242E XOR on Segment

    只有异或操作,无区间翻转,可只用线段树维护。当然,你把上面的代码直接改个if也能过

  • 相关阅读:
    通过filebeat收集并通过elsaticsearch的pipeline功能解析nginx访问日志
    markdown blog Typora+minio+upic图床改造
    spark 使用shc 访问hbase超时问题解决办法
    定制logstash-output-kafka 添加额外事务参数
    《机器学习十讲》第八讲总结
    寒假学习日报(二十四)
    《机器学习十讲》第七讲总结
    寒假学习日报(二十三)
    《机器学习十讲》第六讲总结
    寒假学习日报(二十二)
  • 原文地址:https://www.cnblogs.com/morslin/p/11855281.html
Copyright © 2020-2023  润新知