uva 11402 Ahoy, Pirates!(线段树,lazy propagation)

n长的区间上,定义四种操作:

1)F a b  [a,b]置为1

2)E a b  [a,b]置为0

3)I a b [a,b]取反

4)Q a b 询问sum(a,b)


这种题亦有一种说法叫做染色。。前面两种操作,用一般的区间修改即可完成,对于最关键的取反操作,要根据原来的标记值确定更新后的值。

如,标记:0,1,2分别表示置为0,置为1,取反,-1为未标记

set(x):

if flag(x) == 0 or flag(x) == 1:

set_flag(x, !flag(x))

elif flag(x) == 2:

set_flag(x, -1)

elif flag(x) == -1:

set_flag(x, 2)

x.sum = (length(x) - x.sum)


做此题的时候,发现自己对于 lazy propagation 仍未理解透彻。于是改变了原来从LRJ哪里copy的线段树风格,学习了网上一些优秀的代码。重构了 lazy propagation 的实现方式。


对比新的实现方式和原来的写法,区别在于下面几点:

1)查询操作:原来的方式中,遇到第一个标记了的点就会返回,并且不会在查询中进行 pushdown 操作。

而新方式统一了有标记和无标记的点的查询方式,一边查询,一边 pushdown。

2)更新操作:原来的方式用一个 maintain 函数来统一维护,新方式中将其分拆为用于更新的 set_node (根据父节点和子节点双方的标记值来更新),和用于一般维护的pushup。个人认为后者更易理解。


新实现方式:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <cassert>
#include <algorithm>
#include <cmath>
#include <set>
#include <list>
#include <map>
#include <limits>
using namespace std;

#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define REP(i, s, t) for(int (i)=(s);(i)<=(t);++(i))
#define UREP(i, s, t) for(int (i)=(s);(i)>=(t);--(i))
#define REPOK(i, s, t, o) for(int (i)=(s);(i)<=(t) && (o);++(i))

#define MAXN 1024000
#define MAXM 999999
#define MOD 1000000007

#define PI 3.1415926535897932384626433832795
#define HALF_PI 1.5707963267948966192313216916398

typedef long long LL;
typedef vector<int> veci;
typedef vector<pair<int, int> > vect;
typedef pair<int, int> pairi;

const double maxdouble = numeric_limits<double>::max();
const double eps = 1e-10;
const int INF = 0x7FFFFFFF;

const int maxnode = 1 << 21; // 修改以确保足够大
#define lson(x) ((x)<<1)
#define rson(x) (((x)<<1)|1)
struct IntervalTree {
    int sumv[maxnode + 1];
    int setv[maxnode + 1];
    int length;
    int p, v;
    int qL, qR;

    int _sum;

    void init(int n) {
        length = n;
    }
    //_query的封装
    void query(int L, int R) {
        qL = L;
        qR = R;
        _sum = 0;
        _query(1, 1, length);
    }

    void _query(int o, int L, int R) {
        if (qL <= L && qR >= R) {
            _sum += sumv[o];
        } else {
            int M = L + (R-L)/2;
            int lc = lson(o), rc = rson(o);
            pushdown(o, L, R);
            if (qL <= M)
                _query(lc, L, M);
            if (qR > M)
                _query(rc, M+1, R);
            pushup(o);
        }
    }

    void setto(int L, int R, int v) {
        qL = L;
        qR = R;
        _set(1, 1, length, v);
    }

    void _set(int o, int L, int R, int v) {
        if (qL <= L && qR >= R) {
            set_node(o, L, R, v);
        } else {
            pushdown(o, L, R);
            int M = L + (R-L)/2;
            int lc = lson(o), rc = rson(o);
            if (qL <= M)
                _set(lc, L, M, v);
            if (qR > M)
                _set(rc, M+1, R, v);
            pushup(o);
        }
    }

    void pushdown(int o, int L, int R) {
        if (setv[o] != -1) {
            int lc = lson(o), rc = rson(o), M = L+(R-L)/2;
            set_node(lc, L, M, setv[o]);
            set_node(rc, M+1, R, setv[o]);
            setv[o] = -1;
        }
    }

    void pushup(int o) {
        int lc = lson(o), rc = rson(o);
        sumv[o] = sumv[lc] + sumv[rc];
    }

    void set_node(int o, int L, int R, int v) {
        if (v == 0) {
            setv[o] = 0;
            sumv[o] = 0;
        } else if (v == 1) {
            setv[o] = 1;
            sumv[o] = R - L + 1;
        } else {
            if (setv[o] == 1 || setv[o] == 0) {
                setv[o] = 1^setv[o];
            } else if (setv[o] == 2) {
                setv[o] = -1;
            } else {
                setv[o] = 2;
            }
            sumv[o] = (R - L + 1) - sumv[o];
        }
    }

    void build(char * arr, int o, int L, int R) {
        if (L == R) {
             sumv[o] = arr[L-1] - '0';
             setv[o] = -1;
        } else {
            int M = L + (R-L)/2;
            int lc = 2*o, rc = 2*o+1;
            build(arr, lc, L, M);
            build(arr, rc, M+1, R);
            sumv[o] = sumv[lc] + sumv[rc];
            setv[o] = -1;
        }
    }
};
IntervalTree tree;
char buf[100];
char arr[MAXN+5];

void print() {
        printf("# ");
        int len = tree.length;
        REP(j, 1, len) {
            tree.query(j, j);
            printf("%d ", tree._sum);
        }
        printf("#");
        printf("\n");
}
int main() {
    freopen("input.in", "r", stdin);
    int T, m, t, Q;

    scanf("%d",&T);
    REP(kase, 1, T) {
        printf("Case %d:\n",kase);
        scanf("%d",&m);
        arr[0] = '\0';
        char * p = arr;
        REP(i, 1, m) {
            scanf("%d%s",&t, buf);
            int _l = strlen(buf);
            REP(j, 1, t) {
                strncpy(p, buf, _l);
                p += _l;
            }
        }
        *p = NULL;
        int len = strlen(arr);
        tree.init(len);
        tree.build(arr, 1, 1, len);

        scanf("%d",&Q);
        int l, r;
        int q_cnt = 0;
        //print();
        REP(i, 1, Q) {
            scanf("%s%d%d", buf, &l, &r);
            ++l;++r;
            if (buf[0] == 'F') {
                tree.setto(l, r, 1);
                //print();
            } else if (buf[0] == 'E') {
                tree.setto(l, r, 0);
                //print();
            } else if (buf[0] == 'I') {
                tree.setto(l, r, 2);
                //print();
            } else {
                tree.query(l, r);
                printf("Q%d: %d\n", ++q_cnt, tree._sum);
            }
        }
        //printf("%s\n",arr);
    }

    return 0;
}

Time: 1886ms 2032ms

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值