poj3468 线段树的懒惰标记
题目链接:poj3468
题意:给定一段数组,有两种操作,一种是给某段区间加c,另一种是查询一段区间的和
思路:暴力的方法是每次都给这段区间的点加c,查询也遍历一遍区间,复杂度是n*n,肯定过不去,另一种思路是用线段树记录区间的和,每次查询的复杂度是lgn,修改不必更新到每个点,当某个区间全被修改时,我们可以给它加一个懒惰标记,表示这个区间的所有下面节点都需要更新,只是因为现在不需要使用而暂时没有更新。这样修改的复杂度也降到了lgn
ac代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=1e5+10;
long long num[maxn],sum[maxn*4],lazy[maxn*4];
void pushdown(int rt,int len1,int len2)//向下更新懒惰标记
{
if(lazy[rt])
{
lazy[rt*2]+=lazy[rt];//注意是+=而不是=
lazy[rt*2+1]+=lazy[rt];
sum[rt*2]+=lazy[rt]*len1;
sum[rt*2+1]+=lazy[rt]*len2;
sum[rt]=sum[rt*2]+sum[rt*2+1];
lazy[rt]=0;
}
}
void build(int st,int en,int rt)
{
if(st==en)
{
sum[rt]=num[st];
return;
}
build(st,(st+en)/2,rt*2);
build((st+en)/2+1,en,rt*2+1);
sum[rt]=sum[rt*2]+sum[rt*2+1];
}
void add(int l,int r,int c,int st,int en,int rt)
{
int md=(st+en)/2;
if(l<=st&&r>=en)
{
lazy[rt]+=c;
sum[rt]+=(en-st+1)*c;
return ;
}
pushdown(rt,md-st+1,en-md);
if(r>=md+1)
{
add(l,r,c,md+1,en,rt*2+1);
}
if(l<=md)
{
add(l,r,c,st,md,rt*2);
}
sum[rt]=sum[rt*2]+sum[rt*2+1];
}
long long quer(int l,int r,int rt,int st,int en)
{
long long res=0,md=(st+en)/2;
if(l<=st&&r>=en)
return sum[rt];
pushdown(rt,md-st+1,en-md);
if(r>=md+1)
res+=quer(l,r,rt*2+1,md+1,en);
if(l<=md)
res+=quer(l,r,rt*2,st,md);
return res;
}
int main()
{
char comd;
int n,q;
cin>>n>>q;
for(int i=1;i<=n;i++)
scanf("%lld",&num[i]);
build(1,n,1);
for(int i=1;i<=q;i++)
{
int l,r,c;
cin>>comd;
if(comd=='C')
{
scanf("%d %d %d",&l,&r,&c);
add(l,r,c,1,n,1);
}
else
{
scanf("%d %d",&l,&r);
printf("%lld\n",quer(l,r,1,1,n));
}
}
return 0;
}
提升题:hdu6315
题意:有ab两个数组,有两种操作,一种是给a数组的一段区间加一,另一种是求a/b数组的累加和
思路:只有当一段区间最大的a大于最小的b时,这段区间的答案才会发生改变,如果没有发生改变,那么我们就不必要去给子区间修改最大a的值。我们给这段区间加个懒惰标记就可以了,以后浏览到这个区间时我们再修改。复杂度为nlgn
ac代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=1e5+10;
int sum[maxn*4],maxa[maxn*4],minb[maxn*4],b[maxn],lazy[maxn*4]; void pushup(int rt)
{
sum[rt]=sum[rt*2+1]+sum[rt*2];
maxa[rt]=max(maxa[rt*2],maxa[rt*2+1]);
minb[rt]=min(minb[rt*2],minb[rt*2+1]);
}
void pushdowm(int rt)
{
if(lazy[rt])
{
lazy[rt*2]+=lazy[rt];
lazy[rt*2+1]+=lazy[rt];
maxa[rt*2]+=lazy[rt];
maxa[rt*2+1]+=lazy[rt];
lazy[rt]=0;
}
}
void build(int st,int en,int rt)
{
if(st==en)
{
minb[rt]=b[st];
return;
}
build(st,(st+en)/2,rt*2);
build((st+en)/2+1,en,rt*2+1);
pushup(rt);
}
void add(int l,int r,int st,int en,int rt)
{
int md=(st+en)/2;
pushdowm(rt);
if(l<=st&&r>=en)
{
maxa[rt]++;
if(maxa[rt]>=minb[rt])
{
if(st!=en)
{
add(l,r,md+1,en,rt*2+1);
add(l,r,st,md,rt*2);
pushup(rt);
}
else
{
while(maxa[rt]>=minb[rt])
{
minb[rt]+=b[st];
sum[rt]++;
}
}
}
else
lazy[rt]++;
return;
}
else
{
if(l<=md)
add(l,r,st,md,rt*2);
if(r>=md+1)
add(l,r,md+1,en,rt*2+1);
}
pushup(rt);
}
int quer(int l,int r,int st,int en,int rt)
{
pushdowm(rt);
int md=(st+en)/2;
if(l<=st&&r>=en)
return sum[rt];
int res=0;
if(l<=md)
res+=quer(l,r,st,md,rt*2);
if(r>=md+1)
res+=quer(l,r,md+1,en,rt*2+1);
pushup(rt);
return res;
}
int main()
{
int n,q;
char comd[10];
while(cin>>n>>q)
{
for(int i=0;i<maxn*4;i++)sum[i]=0,maxa[i]=0,minb[i]=0,lazy[i]=0;
for(int i=0;i<maxn;i++)lazy[i]=0; for(int i=1; i<=n; i++)
scanf("%d",&b[i]);
build(1,n,1);
for(int i=1; i<=q; i++)
{
int l,r;
scanf("%s %d %d",&comd,&l,&r);
if(comd[0]=='a')
add(l,r,1,n,1);
else
printf("%d\n",quer(l,r,1,n,1));
}
}
return 0;
}
总结:懒惰标记可以解决一些区域修改问题
poj3468 线段树的懒惰标记的更多相关文章
- HDU 4107 Gangster(线段树 特殊懒惰标记)
两种做法. 第一种:标记区间最大值和最小值,若区间最小值>=P,则本区间+2c,若区间最大值<P,则本区间+c.非常简单的区间更新. 最后发一点牢骚:最后query查一遍就行,我这个2B竟 ...
- HDU 3397 线段树 双懒惰标记
这个是去年遗留历史问题,之前思路混乱,搞了好多发都是WA,就没做了 自从上次做了大白书上那个双重懒惰标记的题目,做这个就思路很清晰了 跟上次大白上那个差不多,这个也是有一个sets标记,代表这个区间全 ...
- HDU 3954 Level up (线段树特殊懒惰标记)
http://blog.csdn.net/acm_cxlove/article/details/7548087 感觉最巧的是定义了min_dis……将区间内有无英雄升级分开处理 #include &l ...
- poj3468 线段树+lazy标记
A Simple Problem with Integers Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 92921 ...
- POJ3468 线段树(区间更新,区间求和,延迟标记)
A Simple Problem with Integers Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 97196 ...
- 线段树初步&&lazy标记
线段树 一.概述: 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点. 对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a, ...
- 【BZOJ-2892&1171】强袭作战&大sz的游戏 权值线段树+单调队列+标记永久化+DP
2892: 强袭作战 Time Limit: 50 Sec Memory Limit: 512 MBSubmit: 45 Solved: 30[Submit][Status][Discuss] D ...
- BZOJ 1798 (线段树||分块)的标记合并
我原来准备做方差的.. 结果发现不会维护两个标记.. 就是操作变成一个 a*x+b ,每次维护a , b 即可 加的时候a=1 ,b=v 乘的时候a=v ,b=0 #include <cstdi ...
- FZU 2171(线段树的延迟标记)
题意:容易理解. 分析:时隔很久,再一次写了一道线段树的代码,之前线段树的题也做了不少,包括各种延迟标记,但是在组队分任务之后,我们队的线段树就交给了另外一个队友在搞, 然后我就一直没去碰线段树的题了 ...
随机推荐
- 反射生成 INSERT 多个对象的 SQL 语句(批量插入)
+ View code private static void insertObject(List<?> objectList) throws IllegalAccessException ...
- 自动化测试基础篇--Selenium弹出框alert
摘自https://www.cnblogs.com/sanzangTst/p/7685304.html 不是所有的弹出框都叫alert,在使用alert方法前,先要识别出到底是不是alert.先认 ...
- f.lux 自动调节显示器色温
我的环境 f.lux 我的使用感受是让屏幕看起来舒服一些,因为我有近视,所以需要保护眼睛. f.lux官网:https://justgetflux.com/ f.lux v4.47 windows 1 ...
- 2. svg学习笔记-svg中的坐标系统和viewbox
我是通过<SVG精髓>这本书学习的svg,说实话,这本书写的不好,或者说翻译的不好,我没有看过这本书的原版,不知道原文写的怎么样,但是翻译出来的有些句子真的很拗口.以前老师给我们API文档 ...
- THINKphp中常见的Request请求类
p($request->domain()); // 获取当前域名 https://jd3.kissneck.com p($request->baseFile()); // 获取当前入口文件 ...
- 百度地图和高德地图结合在web中的使用(二)
百度地图在web中的使用(二) 背景:在做一个关于地理位置字段时,初始位置使用百度地图获取时失败,获取的位置信息不准确,奈何产品说友商好使的啊,F12看后是采用的高德,所以在这采用高德地图获取初始位置 ...
- JAVA的三个版本EE,SE,ME
1998年 SUN发布三个不同版本JAVA,分别是: Java J2EE(Java Platform,Enterprise Edition) JAVA企业版,应用为开发和部署可移植.健壮.可伸缩且安全 ...
- Linux下编译安装redis
redis是开源,BSD许可,高级的key-value存储系统,可以用来存储字符串,哈希结构,链表,集合,因此,常用来提供数据结构服务. redis和memcached相比的独特之处: 1: redi ...
- [福大软工] Z班 第4次成绩排行榜
作业要求 http://www.cnblogs.com/easteast/p/7511234.html 评分细则 (1)博客--15分,分数组成如下: 随笔开头,给出结队两个同学的学号.PS:结对成员 ...
- 【Teradata Utility】系统工具使用
List two ways in which a system utility can be started. Explain how to use the following utilities t ...