线段树单标记下穿【模板】
2018-03-19 12:33
288 查看
#include<iostream> //原谅我又用了好多英文..
#define mid (l+r)/2
using namespace std;
const int maxn=1000000;
long long sum[maxn],flag[maxn],size[maxn]; //sum为求和 flag为懒标记 size为区间长度
int n,m,x,y,z,a[maxn]; //n为元素个数 m为询问个数 x,y为询问区间 z为更改的值 a[]储存元素的值
void build(int t,int l,int r) //建树
{
size[t]=r-l+1; //更新区间长度
if(l==r) //叶子节点返回
{
sum[t]=a[l];
return;
}
build(t*2,l,mid); //递归建树
build(t*2+1,mid+1,r);
sum[t]=sum[t*2]+sum[t*2+1]; //回溯时更新sum
}
void pushdown(int t) //懒标记下传
{
sum[t]+=size[t]*flag[t]; //总和加上区间长度*修改值
if(size[t]!=1) //懒标记下放到两个叶子节点
{
flag[t*2]+=flag[t];
flag[t*2+1]+=flag[t];
}
flag[t]=0; //懒标记清零
}
void add(int t,int l,int r) //区间加
{
pushdown(t); //先更新真实值
if(x<=l&&r<=y) //如果当前区间包含在修改区间中,更新懒标记
{
flag[t]+=z;
return;
}
long long len=min(r,y)-max(l,x)+1; //如果没有在区间中,就找当前区间要修改的元素个数
sum[t]+=len*z; //修改
if(x<=mid)add(t*2,l,mid); //向下递归修改
if(y>mid)add(t*2+1,mid+1,r);
}
long long query(int t,int l,int r) //查询
{
pushdown(t); //懒标记下传,更新当前节点的真实值
if(x<=l&&r<=y) return sum[t];
long long temp=0;
if(x<=mid)temp+=query(t*2,l,mid); //递归询问
if(y>mid)temp+=query(t*2+1,mid+1,r);
return temp; //返回区间和
}
int main()
{
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i]; //读入数据
build(1,1,n); //建树
for(int i=1;i<=m;i++) //询问
{
int que=0;
cin>>que;
if(que==1) //区间修改
{
cin>>x>>y>>z;
add(1,1,n);
}
else //区间求和
{
cin>>x>>y;
cout<<query(1,1,n)<<endl;
}
}
return 0;
}
#define mid (l+r)/2
using namespace std;
const int maxn=1000000;
long long sum[maxn],flag[maxn],size[maxn]; //sum为求和 flag为懒标记 size为区间长度
int n,m,x,y,z,a[maxn]; //n为元素个数 m为询问个数 x,y为询问区间 z为更改的值 a[]储存元素的值
void build(int t,int l,int r) //建树
{
size[t]=r-l+1; //更新区间长度
if(l==r) //叶子节点返回
{
sum[t]=a[l];
return;
}
build(t*2,l,mid); //递归建树
build(t*2+1,mid+1,r);
sum[t]=sum[t*2]+sum[t*2+1]; //回溯时更新sum
}
void pushdown(int t) //懒标记下传
{
sum[t]+=size[t]*flag[t]; //总和加上区间长度*修改值
if(size[t]!=1) //懒标记下放到两个叶子节点
{
flag[t*2]+=flag[t];
flag[t*2+1]+=flag[t];
}
flag[t]=0; //懒标记清零
}
void add(int t,int l,int r) //区间加
{
pushdown(t); //先更新真实值
if(x<=l&&r<=y) //如果当前区间包含在修改区间中,更新懒标记
{
flag[t]+=z;
return;
}
long long len=min(r,y)-max(l,x)+1; //如果没有在区间中,就找当前区间要修改的元素个数
sum[t]+=len*z; //修改
if(x<=mid)add(t*2,l,mid); //向下递归修改
if(y>mid)add(t*2+1,mid+1,r);
}
long long query(int t,int l,int r) //查询
{
pushdown(t); //懒标记下传,更新当前节点的真实值
if(x<=l&&r<=y) return sum[t];
long long temp=0;
if(x<=mid)temp+=query(t*2,l,mid); //递归询问
if(y>mid)temp+=query(t*2+1,mid+1,r);
return temp; //返回区间和
}
int main()
{
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i]; //读入数据
build(1,1,n); //建树
for(int i=1;i<=m;i++) //询问
{
int que=0;
cin>>que;
if(que==1) //区间修改
{
cin>>x>>y>>z;
add(1,1,n);
}
else //区间求和
{
cin>>x>>y;
cout<<query(1,1,n)<<endl;
}
}
return 0;
}
相关文章推荐
- AHOI 2009 行星序列 BZOJ 1798 COGS 1272 线段树模板题:加、乘标记
- 线段树区间更新模板(lazy延迟标记)(1698)
- [模板] - 线段树 - Lazy标记 - 单点/区间更新 - 模板
- SDUT 2880 Devour Magic(线段树lazy和set标记模板)
- 线段树模板 (poj 3468)延迟标记
- 线段树模板(lazy标记)ZOJ 3686
- 郁闷的出纳员 (splay的区间标记模板,删除区间,add标记,类似线段树)
- 算法模板——线段树之Lazy标记
- poj 3468 线段树 lazy标记模板
- POJ3468 A Simple Problem with Integers(线段树区间更新,lazy标记)
- jsp struts模板标记
- hdu 4893 线段树 --- 也是两个变 类似双标记
- 页面模板的标记封装
- leetcode@ [307] Range Sum Query - Mutable / 线段树模板
- hdu 1556 Color the ball(线段树区间更新单点查询+懒惰标记)
- HDU-1698 Just a Hook(线段树模板)
- hdu1166 敌兵布阵(线段树点更新模板题)
- [Usaco2017 Jan]Promotion Counting 线段树合并模板/dfs序
- 南阳OJ 108 士兵杀敌(一)【线段树模板】
- 线段树,不带延迟的模板