线段树区间修改 P3372 模板线段树 1
Posted 古时候的瘾君子
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树区间修改 P3372 模板线段树 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
输出样例#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的主要内容,如果未能解决你的问题,请参考以下文章