fzu 2105 Digits Count (线段树区间更新)

题意:

给你N个数,有四种操作。
(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 opn L R”,求出区间[L,R]的数的和。

解析:

这题思路想到,经过多次操作之后的区间应该是一个数字很多相同的区间:因为如果相邻两个数经过操作之后变成相同的数了,那么再经过覆盖了该区间的操作时,那么他们的值将同时发生改变,变成另外一个相同的值,这多次操作下去,之后将生更多的相同的数字区间,那么可以用一个 cover[o] 来标记这个区间全部相同的值是什么。

my code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define ls (o<<1)
#define rs (o<<1|1)
#define lson ls, L, M
#define rson rs, M+1, R
#define LEN(L, R) (R - L + 1)
using namespace std;
const int N = 1e6 + 10;
int A[N];
int n, m;
int cover[N<<2];

void pushUp(int o) {
    if(cover[ls] != -1 && cover[ls] == cover[rs]) {
        cover[o] = cover[ls];
    }
}

void pushDown(int o) {
    if(cover[o] != -1) {
        cover[ls] = cover[rs] = cover[o];
        cover[o] = -1;
    }
}

void build(int o, int L, int R) {
    cover[o] = -1;
    if(L == R) {
        cover[o] = A[L];
        return ;
    }
    int M = (L + R)/2;
    build(lson);
    build(rson);
    pushUp(o);
}

int query(int o, int L, int R, int ql, int qr) {
    if(ql <= L && R <= qr && cover[o] != -1)
        return cover[o] * LEN(L, R);
    int M = (L + R)/2, ret = 0;
    pushDown(o);
    if(ql <= M) ret += query(lson, ql, qr);
    if(qr > M) ret += query(rson, ql, qr);
    return ret;
}

void modify(int o, int L, int R, int ql, int qr, int val, char oper) {
    if(ql <= L && R <= qr && cover[o] != -1) {
        if(oper == 'A') cover[o] &= val;
        else if(oper == 'O') cover[o] |= val;
        else cover[o] ^= val;
        return ;
    }
    pushDown(o);
    int M = (L + R)/2;
    if(ql <= M) modify(lson, ql, qr, val, oper);
    if(qr > M) modify(rson, ql, qr, val, oper);
    pushUp(o);
}

int main() {
    char oper[5];
    int ql, qr, val;

    int T;
    scanf("%d", &T);
    while(T--) {
        scanf("%d%d", &n, &m);
        for(int i = 0; i < n; i++)
            scanf("%d", &A[i]);
        build(1, 0, n-1);
        while(m--) {
            scanf("%s", oper);
            if(oper[0] == 'S') {
                scanf("%d%d", &ql, &qr);
                printf("%d\n", query(1, 0, n-1, ql, qr));
            }else {
                scanf("%d%d%d", &val, &ql, &qr);
                modify(1, 0, n-1, ql, qr, val, oper[0]);
            }
        }
    }
    return 0;
}

你可能感兴趣的:(FZU,2105)