1. 程式人生 > >線段樹(區間修改,區間求和)

線段樹(區間修改,區間求和)

Description
給出了一個序列,你需要處理如下兩種詢問。

“C a b c”表示給[a, b]區間中的值全部增加c (-10000 ≤ c ≤ 10000)。

“Q a b” 詢問[a, b]區間中所有值的和。

Input
第一行包含兩個整數N, Q。1 ≤ N,Q ≤ 100000.

第二行包含n個整數,表示初始的序列A (-1000000000 ≤ Ai ≤ 1000000000)。

接下來Q行詢問,格式如題目描述。

Output
對於每一個Q開頭的詢問,你需要輸出相應的答案,每個答案一行。

Sample Input
10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4
Sample Output
4
55
9
15

lzay標記,注意query和updata的時候都需要push,並且push的位置不同

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN=100005;
struct node
{
    int l,r;
    long long sum,tag;
}s[4*MAXN];
int a[MAXN];

void build(int l,int r,int x)
{
    s[x].l=l;
    s[x].r=r;
    s
[x].tag=0; if (l==r) { s[x].sum=a[l]; return; } int mid=(l+r)>>1; build(l,mid,2*x); build(mid+1,r,2*x+1); s[x].sum=s[2*x].sum+s[2*x+1].sum; } void push(int x) { s[2*x].tag+=s[x].tag; s[2*x+1].tag+=s[x].tag; s[x].tag=0; s[x].sum=s[2*x].sum+s
[2*x+1].sum+s[2*x].tag*(s[2*x].r-s[2*x].l+1)+s[2*x+1].tag*(s[2*x+1].r-s[2*x+1].l+1); } long long query_sum(int l,int r,int x) { if (s[x].l==l&&s[x].r==r) return s[x].sum+s[x].tag*(r-l+1); long long ret=0; push(x); if (r<=s[2*x].r) ret=query_sum(l,r,2*x); else if (l>=s[2*x+1].l) ret=query_sum(l,r,2*x+1); else { ret+=query_sum(l,s[2*x].r,2*x); ret+=query_sum(s[2*x+1].l,r,2*x+1); } return ret; } void updata(int l,int r,int x,int c) { if (s[x].l==l&&s[x].r==r) { s[x].tag+=c; return; } if (r<=s[2*x].r) updata(l,r,2*x,c); else if (l>=s[2*x+1].l) updata(l,r,2*x+1,c); else { updata(l,s[2*x].r,2*x,c); updata(s[2*x+1].l,r,2*x+1,c); } push(x); } int main() { int i,m,n,l,r,c; char k; cin>>n>>m; for (i=1;i<=n;i++) scanf("%d",&a[i]); build(1,n,1); for (i=1;i<=m;i++) { cin>>k; if (k=='Q') { scanf("%d%d",&l,&r); cout<<query_sum(l,r,1)<<endl; } else { scanf("%d%d%d",&l,&r,&c); updata(l,r,1,c); } } return 0; }