1. 程式人生 > >線段樹區間修改 P3372 【模板】線段樹 1

線段樹區間修改 P3372 【模板】線段樹 1

print alt namespace clu 格式 getch 輸出格式 包含 模板

  

題目描述

如題,已知一個數列,你需要進行下面兩種操作:

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數據範圍內)

樣例說明:

技術分享

線段樹區間修改一般有兩種,一種是區間每個數加上某數,一種是區間每個數都乘上某數,兩種本質上都是一樣的。這題用的是第一種修改。

線段樹的區間修改是用一種延遲標記的思想,也叫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