BZOJ-3155-Preprefix sum(线段树/树状数组)

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

 
 

题解

一道数据结构题

这道题要我们求前缀的前缀和,所以我们就用线段树来维护一下前缀和

对于修改操作,我们假设原值为x1,修改后的值为x,那么就把区间[i,n]都加上x-x1,把a[i]改成x

查询操作我就不讲了

P.s.自己打的快读把左移打成右移,一直RE0.0

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 #define N 100005 
 4 using namespace std;
 5 int n,m,p,x;
 6 int a[N];
 7 ll sum[N];
 8 ll tree[4*N],mark[4*N];
 9 char s[10];
10 int read(){
11     int x=0,f=1; char ch=getchar();
12     while (ch>'9'||ch<'0'){ if (ch=='-') f=-1; ch=getchar(); }
13     while (ch<='9'&&ch>='0'){ x=(x<<3)+(x<<1)+ch-'0'; ch=getchar(); }
14     return x*f;
15 }
16 void up(int v){
17     tree[v]=tree[v<<1]+tree[v<<1|1];
18 }
19 void down(int v,int mid,int l,int r){
20     if (mark[v]){
21         mark[v<<1]+=mark[v];
22         mark[v<<1|1]+=mark[v];
23         tree[v<<1]+=(ll)(mid-l+1)*mark[v];
24         tree[v<<1|1]+=(ll)(r-mid)*mark[v];
25         mark[v]=0;
26     }
27 }
28 void build(int v,int l,int r){
29     if (l==r){
30         tree[v]=sum[l];
31         return;
32     }
33     int mid=(l+r)>>1;
34     build(v<<1,l,mid);
35     build(v<<1|1,mid+1,r);
36     up(v);
37 }
38 void change(int v,int l,int r,int x,int y,int k){
39     if (x<=l&&y>=r){
40         mark[v]+=k;
41         tree[v]+=(ll)(r-l+1)*k;
42         return;
43     }
44     int mid=(l+r)>>1;
45     down(v,mid,l,r);
46     if (y<=mid) change(v<<1,l,mid,x,y,k); else
47     if (x>mid) change(v<<1|1,mid+1,r,x,y,k); else{
48         change(v<<1,l,mid,x,mid,k);
49         change(v<<1|1,mid+1,r,mid+1,y,k);
50     }
51     up(v);
52 }
53 ll query(int v,int l,int r,int x,int y){
54     if (x<=l&&y>=r) return tree[v];
55     int mid=(l+r)>>1;
56     down(v,mid,l,r);
57     if (y<=mid) return query(v<<1,l,mid,x,y); else
58     if (x>mid) return query(v<<1|1,mid+1,r,x,y); else
59     return query(v<<1,l,mid,x,mid)+query(v<<1|1,mid+1,r,mid+1,y);
60 }
61 int main(){
62     n=read(); m=read();
63     for (int i=1;i<=n;i++) a[i]=read();
64     for (int i=1;i<=n;i++) sum[i]=sum[i-1]+(ll)a[i];
65     build(1,1,n);
66     for (int i=1;i<=m;i++){
67         scanf("%s",s);
68         if (s[0]=='Q'){
69             x=read();
70             printf("%lld\n",query(1,1,n,1,x));
71         } else{
72             p=read(); x=read();
73             change(1,1,n,p,n,x-a[p]);
74             a[p]=x;
75         }
76     }
77     return 0;
78 } 
View Code

 

转载于:https://www.cnblogs.com/zhuchenrui/p/7807623.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值