POJ 3468:A Simple Problem with Integers(线段树[成段更新])

题意:N个数Q次操作。一共两种操作:Q l r :询问[l,r]这个区间里的数字和,C l r c: [l,r]区间里的每个数都加上c。1 ≤ N,Q ≤ 100000.

方法:线段树的成段更新。注意懒惰标记。这只是为了有个模板。易错点在代码中以下划线标注。

//16:06
#include <cstdio>
#include <cstring>
#define N 100010
#define lson l, mid, rt<<1
#define rson mid+1, r, rt<<1|1

long long sum[N<<2];
long long col[N<<2];//一直WA,只因这里写成Int。这个和上面那个要同个类型才是。

void pushUp(int rt) {
    sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}

void pushDown(int len, int rt) {
    if (col[rt]) {
        col[rt<<1] += col[rt];
        col[rt<<1|1] += col[rt];
        sum[rt<<1] += (len-len/2)*col[rt];
        sum[rt<<1|1] += (len/2)*col[rt];
        col[rt] = 0;
    }
}

void build(int l, int r, int rt) {
    col[rt] = 0;
if (l==r) {
        scanf("%lld", &sum[rt]);
        return;
    }
    int mid = (l+r)/2;
    build(lson);
    build(rson);
    pushUp(rt);
}

void update(int L, int R, int v, int l, int r, int rt) {
    if (L <= l && r <= R) {
        col[rt] += v;
        sum[rt] += (r-l+1ll)*v;
        return;
    }
    pushDown(r-l+1, rt);
    int mid = (l+r)/2;
    if (L <= mid) update(L,R,v,lson);
    if (R > mid) update(L,R,v,rson);
    pushUp(rt);
}

long long query(int L, int R, int l, int r, int rt) {
    if (L <= l && r <= R) {
        return sum[rt];
    }
    pushDown(r-l+1,rt);
    int mid = (l+r)/2;
    long long ans = 0;
    if (L <= mid) ans += query(L,R,lson);
    if (R > mid) ans += query(L,R,rson);
    return ans;
}


int main() {
    int n, q;
    while (scanf("%d%d", &n, &q) != EOF) {
        build(1,n,1);
        for (int i = 0; i < q; i++) {
            char com[20];
            scanf("%s", com);
            if (com[0] == 'Q') {
                int l, r = 0;
                scanf("%d%d", &l, &r);
                //printf("query %d %d\n", l, r);
                printf("%lld\n", query(l,r,1,n,1));
            } else if (com[0] == 'C') {
                int l, r, add;
                scanf("%d%d%d", &l, &r, &add);
                update(l,r,add,1,n,1);
            }
        }
    }
    return 0;
}

另外感觉三个函数有很多重复点,写了一个紧凑版本,不过看起来代码量差不多,而且效率低了呢。

//16:06
#include <cstdio>
#include <cstring>
#define N 100010
#define lson l, mid, rt<<1
#define rson mid+1, r, rt<<1|1

long long sum[N<<2];
long long col[N<<2];

void pushUp(int rt) {
    sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}

void pushDown(int len, int rt) {
    if (col[rt]) {
        col[rt<<1] += col[rt];
        col[rt<<1|1] += col[rt];
        sum[rt<<1] += (len-len/2)*col[rt];
        sum[rt<<1|1] += (len/2)*col[rt];
        col[rt] = 0;
    }
}

long long basicDo(bool isBuild, int L, int R, int v, int l, int r, int rt) {
    if (isBuild) col[rt] = 0;
    if (l == r || L <= l && r <= R) {
        if (isBuild) scanf("%lld", &sum[rt]);
        col[rt] += v;
        sum[rt] += (r-l+1ll)*v;
        return sum[rt];
    }
    pushDown(r-l+1, rt);
    int mid = (l+r)/2;
    long long ans = 0;
    if (isBuild || L<= mid) ans += basicDo(isBuild,L,R,v,lson);
    if (isBuild || R > mid) ans += basicDo(isBuild,L,R,v,rson);
    pushUp(rt);
    return ans;
}
void build(int l, int r, int rt) {
    basicDo(true, 0,0,0,l,r, rt);
}
void update(int L, int R, int v, int l, int r, int rt) {
    basicDo(false, L, R, v, l, r, rt);
}
long long query(int L, int R, int l, int r ,int rt) {
    return basicDo(false, L, R, 0, l, r, rt);
}


int main() {
    int n, q;
    while (scanf("%d%d", &n, &q) != EOF) {
        build(1,n,1);
        for (int i = 0; i < q; i++) {
            char com[20];
            scanf("%s", com);
            if (com[0] == 'Q') {
                int l, r = 0;
                scanf("%d%d", &l, &r);
                //printf("query %d %d\n", l, r);
                printf("%lld\n", query(l,r,1,n,1));
            } else if (com[0] == 'C') {
                int l, r, add;
                scanf("%d%d%d", &l, &r, &add);
                update(l,r,add,1,n,1);
            }
        }
    }
    return 0;
}

 

posted on 2014-03-19 17:16  ShineCheng  阅读(166)  评论(0编辑  收藏  举报

导航