题目链接: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 线段树的懒惰标记的更多相关文章

  1. HDU 4107 Gangster(线段树 特殊懒惰标记)

    两种做法. 第一种:标记区间最大值和最小值,若区间最小值>=P,则本区间+2c,若区间最大值<P,则本区间+c.非常简单的区间更新. 最后发一点牢骚:最后query查一遍就行,我这个2B竟 ...

  2. HDU 3397 线段树 双懒惰标记

    这个是去年遗留历史问题,之前思路混乱,搞了好多发都是WA,就没做了 自从上次做了大白书上那个双重懒惰标记的题目,做这个就思路很清晰了 跟上次大白上那个差不多,这个也是有一个sets标记,代表这个区间全 ...

  3. HDU 3954 Level up (线段树特殊懒惰标记)

    http://blog.csdn.net/acm_cxlove/article/details/7548087 感觉最巧的是定义了min_dis……将区间内有无英雄升级分开处理 #include &l ...

  4. poj3468 线段树+lazy标记

    A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 92921   ...

  5. POJ3468 线段树(区间更新,区间求和,延迟标记)

    A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 97196   ...

  6. 线段树初步&&lazy标记

    线段树 一.概述: 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点. 对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a, ...

  7. 【BZOJ-2892&1171】强袭作战&大sz的游戏 权值线段树+单调队列+标记永久化+DP

    2892: 强袭作战 Time Limit: 50 Sec  Memory Limit: 512 MBSubmit: 45  Solved: 30[Submit][Status][Discuss] D ...

  8. BZOJ 1798 (线段树||分块)的标记合并

    我原来准备做方差的.. 结果发现不会维护两个标记.. 就是操作变成一个 a*x+b ,每次维护a , b 即可 加的时候a=1 ,b=v 乘的时候a=v ,b=0 #include <cstdi ...

  9. FZU 2171(线段树的延迟标记)

    题意:容易理解. 分析:时隔很久,再一次写了一道线段树的代码,之前线段树的题也做了不少,包括各种延迟标记,但是在组队分任务之后,我们队的线段树就交给了另外一个队友在搞, 然后我就一直没去碰线段树的题了 ...

随机推荐

  1. idea2018版tomcat基本配置

    前言 在配置tomcat之前,要先创建一个javaweb的工程 打开idea的主界面,在菜单中点击File,出现以下的图 点击选择 Application Server 点击选择 Tomcat Ser ...

  2. Fatal error: Can't open and lock privilege tables: Table 'mysql.host' doesn't exist

    今天在用一键安装mysql的shell脚本安装mysql-5.1.73软件后发现mysql始终无法启动,多次执行后依旧报错,只能去查看error日志,发现了如下的2个错误: 错误一:Fatal err ...

  3. LeetCode算法题-Nth Digit(Java实现)

    这是悦乐书的第215次更新,第228篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第83题(顺位题号是400).找到无限整数序列的第n个数字1,2,3,4,5,6,7,8 ...

  4. Python取整函数

    ceil() 向上取整 返回数字的上入整数,如ceil(4.1) 返回 5 ceil()接受的参数必须是数字类型,可以是True或者False,True(代表1),False(代表0),我试了ceil ...

  5. 为JQuery EasyUI 表单组件加上“清除”功能

    1.背景 在使用 EasyUI 各表单组件时,尤其是使用 ComboBox(下拉列表框).DateBox(日期输入框).DateTimeBox(日期时间输入框)这三个组件时,经常有这样的需求,下拉框或 ...

  6. creo2.0安装方法和图文详解教程

    Creo2.0是由PTC公司2012年8月底推出的全新CAD设计软件包,整合了PTC公司的三个软件Pro/Engineer的参数化技术.CoCreate的直接建模技术和ProductView的三维可视 ...

  7. ORCFILE IN HDP 2: BETTER COMPRESSION, BETTER PERFORMANCE

    ORCFILE IN HDP 2: BETTER COMPRESSION, BETTER PERFORMANCE by Carter Shanklin   The upcoming Hive 0.12 ...

  8. 寒假训练——搜索——C - Robot

    The Robot Moving Institute is using a robot in their local store to transport different items. Of co ...

  9. 7.01-beautiful_soup3

    # pip install beautifulsoup4 from bs4 import BeautifulSoup html_doc = """ <html> ...

  10. [Python] 个人TIPS

    1.查询当前代码路径 import os os.getcwd() 2.尝试大文件读取时,可对pandas显示设置进行调整,使之得到更为全局或者局部的细节显示 pd.options.display.ma ...