POJ3468 A Simple Problem with Integers

本文解析了一道经典的线段树成段更新模板题,详细介绍了如何使用线段树进行区间查询与更新,并通过实例代码展示了关键步骤及注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.原题链接: http://poj.org/problem?id=3468

二.题目大意:给出1到N个数,2种操作,Q a b查询从第a个数到第b个数的总和,C a b c从第a个数到第b个数每个数加上c。对于每次查询,输出总和。

三.思路:线段树成段更新模板题。所谓成段更新,就是加一个lazy标记,缓存要增加的元素,每次更新不更新到底,而是累积到lazy数组中,原题为add数组。要进行更深的查询或者更深的更新,用pushDown向下更新,这样就可以避免不必要的更新。

四.代码

#include <cstdio>
#include <cmath>
 
using namespace std;
 
const int MAX_N = 100100;
const int INF = 0x3f3f3f3f;
 
#define LC(t) t<<1
#define RC(t) t<<1|1
 
struct node
{
    int l, r;
    int mid()
    {
        return l+r >> 1;
    }
}seTree[4*MAX_N];
 
long long add[MAX_N<<2],sum[MAX_N<<2];
 
void build(int nd, int l, int r)
{
    seTree[nd].l = l;
    seTree[nd].r = r;
    sum[nd] = add[nd] = 0;
    if(l == r)
        return;
    int mid = seTree[nd].mid();
    build(LC(nd), l, mid);
    build(RC(nd), mid+1, r);
}
 
void pushDown(int nd, int len)
{
    if(!add[nd])
        return;
    add[LC(nd)] += add[nd];
    add[RC(nd)] += add[nd];
    sum[LC(nd)] += add[nd]*(len -(len>>1));
    sum[RC(nd)] += add[nd]*(len>>1);
    add[nd] = 0;
}
 
void pushUp(int nd)
{
    sum[nd] = sum[LC(nd)] + sum[RC(nd)];
}
 
void upDate(int nd, int l, int r,int ele)
{
    if(l == seTree[nd].l && r ==seTree[nd].r){
        sum[nd] += ele*(r-l+1);
        add[nd] += ele;
        return;
    }
 
    if(seTree[nd].l == seTree[nd].r)
        return;
    pushDown(nd, seTree[nd].r-seTree[nd].l+1);
    int mid = seTree[nd].mid();
 
    if(r <= mid)
        upDate(LC(nd), l, r, ele);
    else if(l > mid)
        upDate(RC(nd), l, r, ele);
    else{
        upDate(LC(nd), l, mid, ele);
        upDate(RC(nd), mid+1, r, ele);
    }
    pushUp(nd);
}
 
long long query(int nd, int l,int r)
{
    if(seTree[nd].l == l &&seTree[nd].r == r)
        return sum[nd];
 
    pushDown(nd, seTree[nd].r-seTree[nd].l+1);
    int mid = seTree[nd].mid();
 
    if(r <= mid)
        return query(LC(nd), l, r);
    if(l > mid)
        return query(RC(nd), l, r);
    return query(LC(nd), l, mid) +query(RC(nd), mid+1, r);
}
 
int main()
{
    //freopen("in.txt","r", stdin);
 
    int N, Q, i, ele, a, b, c;
    char ch;
 
    while(~scanf("%d%d", &N,&Q)){
        build(1, 1, N);
 
        for(i = 1; i <= N; i++){
            scanf("%d", &ele);
            upDate(1, i, i, ele);
        }
 
        for(i = 1; i <= Q; i++){
            scanf("\n%c %d %d",&ch, &a, &b);
            if(ch == 'C'){
                scanf("%d", &c);
                upDate(1, a, b, c);
            }
            else
                printf("%I64d\n",query(1, a, b));
        }
    }
    return 0;
}


五. 易错点:本渣还是弄了好久,一开始混淆了线段树的左右边界和要查询和更新的左右边界,然后还犯了奇数整除会损失精度的错误,也就是说len-len/2与len/2是不一样的。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值