洛谷 P3372 【模板】線段樹 1
阿新 • • 發佈:2019-02-18
題目描述
如題,已知一個數列,你需要進行下面兩種操作:
1.將某區間每一個數加上x
2.求出某區間每一個數的和
輸入輸出格式
輸入格式:
第一行包含兩個整數N、M,分別表示該數列數字的個數和操作的總個數。
第二行包含N個用空格分隔的整數,其中第i個數字表示數列第i項的初始值。
接下來M行每行包含3或4個整數,表示一個操作,具體如下:
操作1: 格式:1 x y k 含義:將區間[x,y]內每個數加上k
操作2: 格式:2 x y 含義:輸出區間[x,y]內每個數的和
輸出格式:
輸出包含若干行整數,即為所有操作2的結果。
輸入輸出樣例
輸入樣例#1:
5 5 1 5 4 2 3 2 2 4 1 2 3 2 2 3 4 1 1 5 1 2 1 4
輸出樣例#1: 複製
11 8 20
說明
時空限制:1000ms,128M
資料規模:
對於30%的資料:N<=8,M<=10
對於70%的資料:N<=1000,M<=10000
對於100%的資料:N<=100000,M<=100000
(資料已經過加強^_^,保證在int64/long long資料範圍內)
樣例說明:
PS:裸的線段樹,注意懶標記。
#include <iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<map> #include<queue> #include<set> #include<cmath> #include<stack> #include<string> const int maxn=1e5+10; const int mod=1e9+7; const int inf=1e8; #define me(a,b) memset(a,b,sizeof(a)) typedef long long ll; using namespace std; ll sum[maxn<<2],add[maxn<<2]; void updata(int rt) { sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } void lazy(int l,int r,int rt) { if(add[rt]) { int m=(l+r)>>1; sum[rt<<1]+=(m-l+1)*add[rt]; sum[rt<<1|1]+=(r-m)*add[rt]; add[rt<<1]+=add[rt]; add[rt<<1|1]+=add[rt]; add[rt]=0; } } void build(int l,int r,int rt) { if(l==r) { scanf("%lld",&sum[rt]); return ; } int m=(l+r)>>1; build(l,m,rt<<1); build(m+1,r,rt<<1|1); updata(rt); } void pushdata(int L,int R,int x,int l,int r,int rt) { if(L<=l&&R>=r) { sum[rt]+=(r-l+1)*x; add[rt]+=x; return ; } lazy(l,r,rt); int m=(l+r)>>1; if(L<=m) pushdata(L,R,x,l,m,rt<<1); if(R>m) pushdata(L,R,x,m+1,r,rt<<1|1); updata(rt); } ll getsum(int L,int R,int l,int r,int rt) { if(L<=l&&R>=r) return sum[rt]; lazy(l,r,rt); int m=(l+r)>>1; ll s=0; if(L<=m) s+=getsum(L,R,l,m,rt<<1); if(R>m) s+=getsum(L,R,m+1,r,rt<<1|1); return s; } int main() { int n,m;cin>>n>>m; build(1,n,1); while(m--) { int a,x,y,k; scanf("%d",&a); if(a==1) { scanf("%d%d%d",&x,&y,&k); pushdata(x,y,k,1,n,1); } else { scanf("%d%d",&x,&y); printf("%lld\n",getsum(x,y,1,n,1)); } } return 0; }