B - 一棵普通的线段树
Time Limit: 4000 MS Memory Limit: 256 MB
Submit Status
出题人明天就要半期考试了,课程是《火葬场与波》. 出题人倒在血泊中,一双有力的手摇晃着出题人的肩膀: “同志,醒醒,你还有题没出完呢”. 以下是他的遗言:
给你一个数组 A[1..n]A[1..n],初始值全为 0. 你需要写一棵裸的区间修改、区间查询的线段树, 以支持两个操作. 第一个操作是对区间 [L,R][L,R] 内的数每个数加上 vv. 第二个操作是给出区间 [L,R][L,R] 内所有数的和.
Input
第一行包含两个整数 n(1≤n≤106)n(1≤n≤106) 和 m(1≤m≤106)m(1≤m≤106), 分别是数组的大小和操作的个数.
接下来 mm 行,每行四个用空格分隔的整数 o l r v (1≤l≤r≤n,|v|≤103)o l r v (1≤l≤r≤n,|v|≤103). 如果 o=0o=0,则表示对区间 [l,r][l,r] 内每个数都加上 vv. 否则,请给出区间 [l,r][l,r] 内所有数的和,此时 v≡0v≡0.
Output
对于每个 o≠0o≠0 的操作, 输出包含一个整数的一行,表示对应区间内所有数的和.
Sample Input | Sample Output |
---|---|
5 4 0 2 4 5 1 3 5 0 0 1 3 -2 1 1 5 0 |
10 9 |
Sample input and output
#include <cstdio> #include <iostream> #include <cstring> #include <cstring> #include <algorithm> using namespace std; const int MAX_N = 100010; int s[MAX_N<<2],col[MAX_N<<2]; void up(int p){ s[p] = s[p*2] + s[p*2+1]; } void build(int p,int l,int r){ if(l==r){ s[p] = 0; col[p] = 0; return ; } int mid =(l+r)>>1; build(p*2,l,mid); build(p*2+1,mid+1,r); up(p); } void down(int p,int l,int r){ if(col[p]){ int mid =(l+r)>>1; col[p*2]+=col[p]; col[p*2+1]+=col[p]; s[p*2] += col[p]*(mid-l+1); s[p*2+1] += col[p]*(r-mid); col[p] = 0; return ; } } void change(int p,int l,int r,int x,int y,int v){ if(x<=l&&r<=y){ col[p] += v; s[p]+=(r-l+1)*v; return; } int mid = (l+r)>>1; down(p,l,r); if(x<=mid) change(p*2,l,mid,x,y,v); if(y>mid) change(p*2+1,mid+1,r,x,y,v); up(p); } int query(int p,int l,int r,int x,int y){ if(x<=l&&r<=y){ return s[p]; } down(p,l,r); int mid = (l+r)>>1,res = 0; if(x<=mid) res+=query(p*2,l,mid,x,y); if(y>mid) res+=query(p*2+1,mid+1,r,x,y); return res; } int main(){ int n,m; scanf("%d%d",&n,&m); build(1,1,n); while(m--){ int a,b,c,v; scanf("%d%d%d%d",&a,&b,&c,&v); if(a==0){ change(1,1,n,b,c,v); } else if(a==1){ printf("%d\n",query(1,1,n,b,c)); } } return 0; }