線段樹區間修改 P3372 【模板】線段樹 1
阿新 • • 發佈:2017-07-14
print alt namespace clu 格式 getch 輸出格式 包含 模板
輸出樣例#1:
題目描述
如題,已知一個數列,你需要進行下面兩種操作:
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
11 8 20
說明
時空限制:1000ms,128M
數據規模:
對於30%的數據:N<=8,M<=10
對於70%的數據:N<=1000,M<=10000
對於100%的數據:N<=100000,M<=100000
(數據已經過加強^_^,保證在int64/long long數據範圍內)
樣例說明:
線段樹區間修改一般有兩種,一種是區間每個數加上某數,一種是區間每個數都乘上某數,兩種本質上都是一樣的。這題用的是第一種修改。
線段樹的區間修改是用一種延遲標記的思想,也叫lazy-tag思想,其思想通俗點講就是將當前節點標記,需要訪問其子節點時,傳遞延遲標記,並消除此節點標記。
代碼:
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #define ll long long using namespace std; int gi() { int x=0,y=1; char ch=getchar(); while(ch<‘0‘||ch>‘9‘) { if(ch==‘-‘) y=-1; ch=getchar(); } while(ch>=‘0‘&&ch<=‘9‘) { x=x*10+ch-‘0‘; ch=getchar(); } return x*y; } ll gl() { ll x=0,y=1; char ch=getchar(); while(ch<‘0‘||ch>‘9‘) { if(ch==‘-‘) y=-1; ch=getchar(); } while(ch>=‘0‘&&ch<=‘9‘) { x=x*10+ch-‘0‘; ch=getchar(); } return x*y; } ll a[100045],tree[400045],lazy[400045]; void tag(int rt,int l,int r) { if(l==r) return; if(lazy[rt]) { int m=(l+r)>>1; tree[rt*2]+=lazy[rt]*(m-l+1); tree[rt*2+1]+=lazy[rt]*(r-m); lazy[rt*2]+=lazy[rt]; lazy[rt*2+1]+=lazy[rt]; lazy[rt]=0; } } void update(int rt,int l,int r,int L,int R,ll change) { if(L<=l&&R>=r) { tree[rt]+=change*(r-l+1); lazy[rt]+=change; return; } tag(rt,l,r); int m=(r+l)>>1; if(L<=m)update(rt*2,l,m,L,R,change); if(R>m)update(rt*2+1,m+1,r,L,R,change); tree[rt]=tree[rt*2]+tree[rt*2+1]; } ll query(int rt,int l,int r,int L,int R) { tag(rt,l,r); if(L<=l&&R>=r) return tree[rt]; int m=(l+r)>>1; ll ans=0; if(L<=m) ans+=query(rt*2,l,m,L,R); if(R>m) ans+=query(rt*2+1,m+1,r,L,R); return ans; } int main() { int n=gi(),m=gi(),p,x,y; ll k; for(int i=1;i<=n;i++) update(1,1,100045,i,i,gl()); for(int i=1;i<=m;i++) { p=gi(); if(p==1) { x=gi(),y=gi(),k=gl(); update(1,1,100045,x,y,k); } else { x=gi(),y=gi(); printf("%lld\n",query(1,1,100045,x,y)); } } return 0; }
線段樹區間修改 P3372 【模板】線段樹 1