bzoj3155 Preprefix sum(简单线段树)

3155: Preprefix sum

Time Limit: 1 Sec  Memory Limit: 512 MB
Submit: 1258  Solved: 573
[Submit][Status][Discuss]

Description

Input

第一行给出两个整数N,M。分别表示序列长度和操作个数

接下来一行有N个数,即给定的序列a1,a2,....an

接下来M行,每行对应一个操作,格式见题目描述

Output

对于每个询问操作,输出一行,表示所询问的SSi的值。

Sample Input

5 3

1 2 3 4 5

Query 5

Modify 3 2

Query 5

Sample Output

35

32

HINT

1<=N,M<=100000,且在任意时刻0<=Ai<=100000

Source


Katharon+#1



水题。

先考虑一下,若将题面中“将ai改为x”换成“ai加上x”,则对于其前缀和序列bi来说,是对bi-bn这段区间上所有数加x,对于查询前缀和的前缀和来说,实质是查询bi序列的某段和。

那么其实”将ai改为x“就是”ai加上x-ai“,按照上述思路,用线段树维护前缀和序列即可

附AC代码:

</pre><pre code_snippet_id="1962370" snippet_file_name="blog_20161102_1_9101974" name="code" class="cpp">
</pre><pre code_snippet_id="1962370" snippet_file_name="blog_20161102_1_9101974" name="code" class="cpp">
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<climits>
#define N 200001
#define M 1600001
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
ll n,m;char ch[101];
ll a[N],b[N],c[N];
struct edge{ll l,r,val,tag;}e[M];
void pushdown(ll u)
{
    if(e[u].l==e[u].r)return;
    if(e[u].tag)
        {
            ll tag=e[u].tag;
            e[u<<1].val+=tag*(e[u<<1].r-e[u<<1].l+1);e[u<<1].tag+=tag;
            e[u<<1|1].val+=tag*(e[u<<1|1].r-e[u<<1|1].l+1);e[u<<1|1].tag+=tag;
            e[u].tag=0;
        }
}
void pushup(ll u){e[u].val=e[u<<1].val+e[u<<1|1].val;}
void build(ll u,ll l,ll r)
{
    e[u].l=l,e[u].r=r;
    if(l==r){e[u].val=b[l];return;}
    e[u].val=0;
    ll mid=(l+r)>>1;
    build(u<<1,l,mid);build(u<<1|1,mid+1,r);
    pushup(u);
}
void change(ll u,ll x,ll y,ll c)
{
    ll l=e[u].l,r=e[u].r;
    pushdown(u);
    if(x==l&&y==r)
        {
            e[u].tag+=c;
            e[u].val+=c*(r-l+1);
            return;
        }
    ll mid=(l+r)>>1;
    if(y<=mid)change(u<<1,x,y,c);
    else if(x>mid)change(u<<1|1,x,y,c);
    else
        {
            change(u<<1,x,mid,c);
            change(u<<1|1,mid+1,y,c);
        }
    pushup(u);
}
ll query(ll u,ll x,ll y)
{
    ll l=e[u].l,r=e[u].r;
    pushdown(u);
    if(x<=l&&y>=r)return e[u].val;
    ll mid=(l+r)>>1;
    if(y<=mid)return query(u<<1,x,y);
    else if(x>mid)return query(u<<1|1,x,y);
    else return query(u<<1,x,mid)+query(u<<1|1,mid+1,y);
}
int main()
{
//  freopen("in.txt","r",stdin);
//  freopen("my.txt","w",stdout);
    ll x;
    scanf("%lld%lld",&n,&m);
    for(ll i=1;i<=n;i++){scanf("%lld",&a[i]);b[i]=b[i-1]+a[i];}
    build(1,1,n);
    for(ll i=1;i<=m;i++)
        {
            ll s,t;
            scanf("%s%lld",ch,&s);
            if(ch[0]=='M')
                {
                    scanf("%lld",&t);
                    x=t-a[s];a[s]=t;
                    change(1,s,n,x);
                }
            else
                printf("%lld\n",query(1,1,s));
        }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值