[FZU 2105 Digits Count] 线段树区间的复合操作

[FZU 2105 Digits Count] 线段树区间复合操作

题目链接[FZU 2105 Digits Count] 
题意描述:给定N个数。每个数在[0, 15] 范围内。(1 <= N <= 1000000)有四种区间操作:
  1. AND opn L, R 表示区间[L, R] 的所有数字与opn 进行与操作
  2. OR opn L, R 表示区间[L, R] 的所有数字与opn 进行或操作
  3. XOR opn L, R 表示区间[L, R] 的所有数字与opn 进行异或操作
  4. SUM L,R 求区间[L, R] 的所有数字之和
0 <=opn <= 15
解题思路:很不错的一道线段树。四个二进制位能够表示出每个数字。然后可以用四个线段树分别维护每一位在区间[L, R] 的1 的个数,把每一位单独拿出来这样就很方便进行位运算操作了。与 0 操作就相当于区间置0, 或1 操作就相当于区间置1, 异或1 操作就相当于区间翻转(0变1, 1 变0)。求出每一位在区间[L, R] 的个数, 很容易就可以得到答案了。
但是要注意一下, 在这里要考虑一下位运算的先后顺序。
比如:
(x | 1) ^ 1 = 1 ^ 1 = x & 0,  BUT,  (x ^ 1) |  1 = x | 1;
(x & 0) ^ 1 = 0 ^ 1 = x | 1,  BUT,  (x ^ 1) & 0 =  x & 0;
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

#pragma comment(linker, "/STACK:1024000000,1024000000")

#define FIN             freopen("input.txt","r",stdin)
#define FOUT            freopen("output.txt","w",stdout)
#define fst             first
#define snd             second
#define lson            l, mid, (rt << 1)
#define rson            mid + 1, r, (rt << 1 | 1)

typedef __int64 LL;
//typedef long long LL;
typedef pair<int, int> PII;

const int MAXN = 1000000 + 5;

template <class T>
inline bool scan_d (T &ret) {
    char c;
    int sgn;
    if (c = getchar(), c == EOF) return 0; //EOF
    while (c != '-' && (c < '0' || c > '9') ) c = getchar();
    sgn = (c == '-') ? -1 : 1;
    ret = (c == '-') ? 0 : (c - '0');
    while (c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
    ret *= sgn;
    return 1;
}

struct Seg {
    struct SNode {
        int sum;
        bool tag[3];
    } node[MAXN << 2];
    void init() {
        memset (node, 0, sizeof (node) );
    }
    inline void pushUp (int rt) {
        node[rt].sum = node[rt << 1].sum + node[rt << 1 | 1].sum;
    }
    inline void pushDown (int w, int rt) {
        if (node[rt].tag[2]) {
            if (node[rt << 1].tag[0]) {
                /// (x & 0) ^ 1 => 0 ^ 1 => x | 1
                node[rt << 1].tag[0] = 0;
                node[rt << 1].tag[1] = 1;
                node[rt << 1].sum = w - (w >> 1);
            } else if (node[rt << 1].tag[1]) {
                /// (x | 1) ^ 1 = 1 ^ 1 = x & 0
                node[rt << 1].tag[0] = 1;
                node[rt << 1].tag[1] = 0;
                node[rt << 1].sum = 0;
            } else {
                node[rt << 1].tag[2] ^= 1;
                node[rt << 1].sum = w - (w >> 1) - node[rt << 1].sum;
            }
            if (node[rt << 1 | 1].tag[0]) {
                /// (x & 0) ^ 1 => 0 ^ 1 => x | 1
                node[rt << 1 | 1].tag[0] = 0;
                node[rt << 1 | 1].tag[1] = 1;
                node[rt << 1 | 1].sum = (w >> 1);
            } else if (node[rt << 1 | 1].tag[1]) {
                /// (x | 1) ^ 1 = 1 ^ 1 = x & 0
                node[rt << 1 | 1].tag[0] = 1;
                node[rt << 1 | 1].tag[1] = 0;
                node[rt << 1 | 1].sum = 0;
            } else {
                node[rt << 1 | 1].tag[2] ^= 1;
                node[rt << 1 | 1].sum = (w >> 1) - node[rt << 1 | 1].sum;
            }
            node[rt].tag[2] = 0;
        }
        if (node[rt].tag[0]) {
            node[rt << 1].sum = node[rt << 1 | 1].sum = 0;
            node[rt << 1].tag[0] = node[rt << 1 | 1].tag[0] = 1;
            node[rt << 1].tag[1] = node[rt << 1 | 1].tag[1] = 0;
            node[rt << 1].tag[2] = node[rt << 1 | 1].tag[2] = 0;
            node[rt].tag[0] = 0;
        }
        if (node[rt].tag[1]) {
            node[rt << 1].sum = w - (w >> 1);
            node[rt << 1 | 1].sum = w >> 1;
            node[rt << 1].tag[0] = node[rt << 1 | 1].tag[0] = 0;
            node[rt << 1].tag[1] = node[rt << 1 | 1].tag[1] = 1;
            node[rt << 1].tag[2] = node[rt << 1 | 1].tag[2] = 0;
            node[rt].tag[1] = 0;
        }
    }
    int query (int L, int R, int l, int r, int rt) {
        if (L <= l && r <= R) {
            return node[rt].sum;
        }
        int mid = (l + r) >> 1, ret = 0;
        pushDown (r - l + 1, rt);
        if (L <= mid) ret = query (L, R, lson);
        if (R > mid) ret += query (L, R, rson);
        return ret;
    }
    /// AND
    void update1 (int L, int R, int l, int r, int rt) {
        if (L <= l && r <= R) {
            node[rt].sum = 0;
            node[rt].tag[0] = 1;
            node[rt].tag[1] = 0;
            node[rt].tag[2] = 0;
            return;
        }
        pushDown (r - l + 1, rt);
        int mid = (l + r) >> 1;
        if (L <= mid) update1 (L, R, lson);
        if (R > mid) update1 (L, R, rson);
        pushUp (rt);
    }
    /// OR
    void update2 (int L, int R, int l, int r, int rt) {
        if (L <= l && r <= R) {
            node[rt].sum = r - l + 1;
            node[rt].tag[0] = 0;
            node[rt].tag[1] = 1;
            node[rt].tag[2] = 0;
            return;
        }
        int mid = (l + r) >> 1;
        pushDown (r - l + 1, rt);
        if (L <= mid) update2 (L, R, lson);
        if (R > mid) update2 (L, R, rson);
        pushUp (rt);
    }
    /// XOR
    void update3 (int L, int R, int l, int r, int rt) {
        if (L <= l && r <= R) {
            node[rt].tag[2] ^= 1;
            node[rt].sum = (r - l + 1) - node[rt].sum;
            if (node[rt].tag[0] && node[rt].tag[2]) {
                /// (x & 0) ^ 1 => 0 ^ 1 => x | 1
                node[rt].tag[0] = 0;
                node[rt].tag[1] = 1;
                node[rt].tag[2] = 0;
                node[rt].sum = r - l + 1;
            } else if (node[rt].tag[1] && node[rt].tag[2]) {
                /// (x | 1) ^ 1 = 1 ^ 1 = x & 0
                node[rt].tag[0] = 1;
                node[rt].tag[1] = 0;
                node[rt].tag[2] = 0;
                node[rt].sum = 0;
            }
            return;
        }
        int mid = (l + r) >> 1;
        pushDown (r - l + 1, rt);
        if (L <= mid) update3 (L, R, lson);
        if (R > mid) update3 (L, R, rson);
        pushUp (rt);
    }
} seg[4];
void build (int l, int r, int rt) {
    if (l == r) {
        int x, y;
        scan_d (x);
        for (int i = 0; i < 4; i ++) {
            y = x & (1 << i);
            if (y) seg[i].node[rt].sum = 1;
        }
        return;
    }
    int mid = (l + r) >> 1;
    build (lson);
    build (rson);
    for (int i = 0; i < 4; i++) {
        seg[i].pushUp (rt);
    }
}
int T, N, M;
int res;
char buf[15];
int main() {
#ifndef ONLINE_JUDGE
    FIN;
//    FOUT;
#endif // ONLINE_JUDGE
    int L, R, v;
    scan_d (T);
    while (T --) {
        scan_d (N);
        scan_d (M);
        for (int i = 0; i < 4; i++) {
            seg[i].init();
        }
        build (1, N, 1);
        while (M --) {
            scanf ("%s", buf);
            switch (buf[0]) {
            case 'A':
                scan_d (v);
                scan_d (L);
                scan_d (R);
                L ++, R ++;
                for (int i = 0; i < 4; i++) {
                    int x = v & (1 << i);
                    if (!x) {
                        seg[i].update1 (L, R, 1, N, 1);
                    }
                }
                break;
            case 'O':
                scan_d (v);
                scan_d (L);
                scan_d (R);
                L ++, R ++;
                for (int i = 0; i < 4; i++) {
                    int x = v & (1 << i);
                    if (x) {
                        seg[i].update2 (L, R, 1, N, 1);
                    }
                }
                break;
            case 'X':
                scan_d (v);
                scan_d (L);
                scan_d (R);
                L ++, R ++;
                for (int i = 0; i < 4; i++) {
                    int x = v & (1 << i);
                    if (x) {
                        seg[i].update3 (L, R, 1, N, 1);
                    }
                }
                break;
            case 'S':
                scan_d (L);
                scan_d (R);
                L ++, R ++;
                res = 0;
                for (int i = 3; i >= 0; i--) {
                    int x;
                    x = seg[i].query (L, R, 1, N, 1);
                    res = (res << 1) + x;
                }
                printf ("%d\n", res);
                break;
            }
        }
    }
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值