POJ

来源:互联网 发布:手机淘宝网银怎么开通 编辑:程序博客网 时间:2024/06/07 23:28

题目链接

POJ-3468

题目大意

n个数,q个操作,操作分为两种:
Cabc,表示将区间[a,b]都加上c(10000c10000)
Qab,表示询问区间[a,b]的和。

数据范围

1n,q100000
1e9ai1e9

解题思路

线段树模板,区间修改,区间求和。

学到这线段树才算刚入门,写一下这个lazy思想。有句话说得好:偷懒促进社会进步。lazy思想也差不多。
lazy思想主要体现在“要”的时候才去“拿”,体现在代码上就是update和query操作稍微修改了一下。
这是区间修改,如果再像单点修改那样,每次递归到最底层,更新之后返回,那还不如直接暴力改!如果要更新的区间完全包含当前节点所管辖的区间,那就直接在当前节点上更新就完了,(其实一般查询的时候也用到了类似的思想),像这样:

if(L <= tree[rt].l && tree[rt].r <= R) {        tree[rt].sum += (LL)(tree[rt].r - tree[rt].l + 1) * val;        lazy[rt] += (LL)val;        return ;}

如果不完全包含,则将lazy标记下放到左右儿子上,即push_down操作,并将当前节点的lazy标记清零。
详见代码



AC代码:

//线段树--区间修改(Lazy标记),区间求和#include <cstdio>#include <cstring>#include <cstdlib>#include <cmath>#include <algorithm>#include <set>#include <map>#include <queue>using namespace std;typedef long long LL;const int inf = 1 << 30;const LL INF = 1LL << 60;const int MaxN = 100010;//这里MaxN = 100000死活过不了!!!int n, q;LL a[MaxN + 5];struct segtree{    LL l, r;    LL sum;}tree[4 * MaxN + 5];LL lazy[4 * MaxN + 5];//lazy[i]表示i节点所管辖的区间应该加的值void push_up(LL rt) {    tree[rt].sum = tree[rt << 1].sum + tree[rt << 1 | 1].sum;}void push_down(LL rt) {    //理解了lazy的含义,这里就应该很好理解    if(lazy[rt] ) {        tree[rt << 1].sum += (tree[rt << 1].r - tree[rt << 1].l + 1) * lazy[rt];        tree[rt << 1 | 1].sum += (tree[rt << 1 | 1].r - tree[rt << 1 | 1].l + 1) * lazy[rt];        lazy[rt << 1] += lazy[rt];        lazy[rt << 1 | 1] += lazy[rt];        lazy[rt] = 0; //完成下放之后应该将当前节点的lazy标记清零    }}void Build(LL rt, LL l, LL r) {    tree[rt].l = l, tree[rt].r = r;    if(l == r) {        tree[rt].sum = a[l];        return;    }    LL mid = (l + r) >> 1;    Build(rt << 1, l, mid);    Build(rt << 1 | 1, mid + 1, r);    //tree[rt].sum = tree[rt << 1].sum + tree[rt << 1 | 1].sum;    push_up(rt);}void update(LL rt, LL L, LL R, LL val){    //如果要更新的区间包含当前节点所代表的区间,    //则直接更新这个节点,不再往下更新,并给当前节点打上lazy标记    if(L <= tree[rt].l && tree[rt].r <= R) {        tree[rt].sum += (LL)(tree[rt].r - tree[rt].l + 1) * val;        lazy[rt] += (LL)val;        return ;    }    //否则,下放lazy标记 并更新左右儿子    push_down(rt);    LL mid = (tree[rt].l + tree[rt].r) >> 1;    if(L <= mid)        update(rt << 1, L, R, val);    if(R > mid)        update(rt << 1 | 1, L, R, val);    //tree[rt].sum = tree[rt << 1].sum + tree[rt << 1 | 1].sum;    push_up(rt);}LL query(LL rt, LL L, LL R) {    //若要查询的区间完全包含当前节点的区间,则直接返回当前节点的sum    if(L <= tree[rt].l && tree[rt].r <= R)        return tree[rt].sum;    //否则,先下放lazy标记,再进行 左右儿子的查询    push_down(rt);    LL mid = (tree[rt].l + tree[rt].r) >> 1;    LL res = 0;    if(L <= mid) res += query(rt << 1, L, R);    if(R > mid) res += query(rt << 1 | 1, L, R);    return res;}int main(){    while(scanf("%d %d", &n, &q) != EOF)    {        for(int i = 1; i <= n; i++) scanf("%lld", &a[i]);        Build(1, 1, n);        for(int i = 1; i <= q; i++) {            char c;            scanf(" %c", &c);            if(c == 'Q') {                LL l, r;                scanf("%lld %lld", &l, &r);                LL ans = query(1, l, r);                printf("%lld\n", ans);            }            else if(c == 'C') {                LL l, r;                LL val;                scanf("%lld %lld %lld", &l, &r, &val);                update(1, l, r, val); //区间更新            }        }    }    return 0;}
原创粉丝点击