传送门luoguP2894

本题我们要维护最左边的值,考虑使用线段树维护。我们发现只用一个来存储当前的节点的值并不够,因为对于一个节点我们无法用一个来描述这整个区间哪些为空,哪些满了,例如查询的跨越了两个区间,我们就无法找到最左边的了。
所以我们考虑用多个变量描述该区间的状态:
lmx表示该区间最左边连续为空的个数,
rmx表示该区间最右边连续为空的个数,
len表示整个区间的总房间数,
sum表示整个区间的总空房间数。
这样我们可以很好的描述状态了,
对于一个节点的左房间数等于t[k].lmx,
若左儿子全空即t[lc].len=t[lc].sum,那么t[k].lmx=t[lc].sum+t[rc].lmx,
同理于右节点。
对于横跨两个节点的区间,
等于t[lc].rmx+t[rc].lmx左儿子的右房间数+右儿子的左房间数,
由于是区间更新,所以我们还要使用lazy_tag来做,
核心介绍完了,代码实现:

#include<bits/stdc++.h>
using namespace std;
#define lc k<<1
#define rc k<<1|1const int N=5e5+5;
int n,m;
struct node
{int lz,sum,len,lmx,rmx,l,r;//该节点懒惰标记,最大连续空房间数,房间总数,左边连续空房间数,右边连续空房间数
}t[N<<2];//4倍以上 inline void pushdown(int k)
{if(t[k].lz==0) return;if(t[k].lz==1)//开房 {t[lc].lz=t[rc].lz=1;t[lc].lmx=t[lc].rmx=t[lc].sum=0;t[rc].lmx=t[rc].rmx=t[rc].sum=0;}if(t[k].lz==2)//退房 {t[lc].lz=t[rc].lz=2;t[lc].lmx=t[lc].rmx=t[lc].sum=t[lc].len;t[rc].lmx=t[rc].rmx=t[rc].sum=t[rc].len;}t[k].lz=0;//清空当前的懒标
}inline void pushup(int k)
{if(t[lc].sum==t[lc].len) t[k].lmx=t[lc].len+t[rc].lmx; else t[k].lmx=t[lc].lmx;//如果左儿子全部空,那么父节点的左边连续最大值为左儿子加右儿子的左边 if(t[rc].sum==t[rc].len) t[k].rmx=t[lc].rmx+t[rc].len;//同理 else t[k].rmx=t[rc].rmx;t[k].sum=max(max(t[lc].sum,t[rc].sum),t[lc].rmx+t[rc].lmx);//整个区间连续最大值为左儿子,右儿子,跨越了左右的最大值
}inline void build(int k,int l,int r)
{t[k].l=l;t[k].r=r;//不要忘了初始化节点对于的一段区间 t[k].lmx=t[k].rmx=t[k].sum=t[k].len=r-l+1;//初始全是空,总的左边的右边的全部空的 t[k].lz=0;if(l==r) return;//到叶子节点找完了 int mid=(l+r)>>1;build(lc,l,mid);//建左儿子 build(rc,mid+1,r);//建右儿子
}inline void update(int k,int l,int r,int tag)
{pushdown(k);//下传懒标 if(t[k].l>=l && t[k].r<=r) //如果覆盖了这个区间 {if(tag==1) t[k].lmx=t[k].rmx=t[k].sum=0; //如果是开房,就全部更新为0 else t[k].lmx=t[k].rmx=t[k].sum=t[k].len;//否则全部为空 t[k].lz=tag;return;}int mid=(t[k].l+t[k].r)>>1;if(l<=mid) update(lc,l,r,tag); //在左区间 if(r>mid) update(rc,l,r,tag);//在右区间 pushup(k);//更新
}inline int query(int k,int val)
{pushdown(k);//下传懒标 if(t[k].l==t[k].r) return t[k].l;//找到了返回左节点 int mid=(t[k].l+t[k].r)>>1;if(t[lc].sum>=val) return query(lc,val);//注意:是找尽量左边的,所以先找左,再找中,再找右 if(t[lc].rmx+t[rc].lmx>=val) return mid-t[lc].rmx+1;if(t[rc].sum>=val) return query(rc,val);
}int main()
{scanf("%d%d",&n,&m);build(1,1,n);//构建线段树 int x,y,cas;for(int i=1;i<=m;i++){scanf("%d",&cas);if(cas==1)//如果开房 {scanf("%d",&x);if(t[1].sum>=x)//判断整个区间是否装的下,否则输出0 {int left=query(1,x);//查询左节点 cout<<left<<endl;update(1,left,left+x-1,cas);//整个区间全部满,更新为1 }else cout<<0<<endl;}else{scanf("%d%d",&x,&y);update(1,x,x+y-1,cas);//整个区间变空,更新为0 }}return 0;
}

线段树应用:区间合并相关推荐

  1. [HDOJ3308]LCIS(线段树,区间合并)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308 题意:给定n个数,两个操作: U A B:将位置A的数值改成B Q A B:查询[A,B]内最长 ...

  2. 线段树练习——区间合并

    这类题目会询问区间中满足条件的连续最长区间,所以PushUp的时候需要对左右儿子的区间进行合并(这里最难理解) hdu 3308 http://acm.hdu.edu.cn/showproblem.p ...

  3. hdu 5052 树链剖分+线段树+区间合并

    各种裸,但合在一起好恶心... 因为路径是有向的,所以要维护区间里向两个方向走的最大收益和区间里的最大最小值,要用到区间合并的线段树 #include <iostream> #includ ...

  4. 【线段树_区间合并_异或翻转】HDU 3911 Black And White

    HDU 3911 Black And White 题意:有一个只有0和1组成的序列.对这个序列有两个操作:(1)对区间进行翻转.也就是0变1,1变0.  (2)查询区间连续1的序列的最大长度 区间合并 ...

  5. 喵哈哈村的冒菜店-(线段树的区间合并)

    喵哈哈村的冒菜店 发布时间: 2017年3月19日 16:00   最后更新: 2017年3月19日 16:01   时间限制: 1000ms   内存限制: 128M 描述 喵哈哈村的冒菜店开张了, ...

  6. hdu 3911 线段树+区间合并

    模板题 #include <iostream> #include <cstdio> #include <algorithm> #include <cstrin ...

  7. Codeforces Round #742 (Div. 2) E. Non-Decreasing Dilemma (线段树维护区间连续问题)

    题意: 操作1:把x位置的数字修改成y. 操作2:查询[l,r]之间不下降序列的个数. 题解: 线段树维护区间和问题 (这是套路,想不到只能说做题少别打我) . 用五个变量进行维护. sum区间总个数 ...

  8. 线段树分裂与合并 ----- P2824 [HEOI2016/TJOI2016]排序 [线段树分裂合并 OR 01序列排序+二分线段树]

    题目链接 题目大意: 对一个序列,每次按照升序或者降序排序序列某一段,问你最后的序列是什么? 解法1:二分+线段树 首先我们知道对一个01序列进行排序是很快的!我们只要知道里面有多少个1和多少个0,那 ...

  9. BZOJ1018 | SHOI2008-堵塞的交通traffic——线段树维护区间连通性+细节

    [题目描述] BZOJ1018 | SHOI2008-堵塞的交通traffic 有一天,由于某种穿越现象作用,你来到了传说中的小人国.小人国的布局非常奇特,整个国家的交通系统可 以被看成是一个2行C列 ...

  10. 【线段树】区间修改(区间覆盖、区间权值加)标记下放操作的逻辑顺序

    洛谷传送门:月下"毛景树" 由于没有合适的题目,就从这道题入手,解此题时用到的算法/数据结构包括: 树链剖分 线段树(区间覆盖.区间加.区间查询.单点修改) 这道题被我调试了四个小 ...

最新文章

  1. 深度学习综述:Hinton、Yann LeCun和Bengio经典重读
  2. 遭遇错误:ORA-01031
  3. 盘丝洞服务器维护,9月27日“盘丝洞”等服务器停机更新
  4. HttpWebRequest WebResponse 对象简单了解
  5. CAS单点登录0-原理
  6. C语言多项式乘法模拟,急!!!!c语言:求n次多项式的加法和乘法
  7. NLP复习资料(5)-第九章 句法分析
  8. 16位的数字高字节和低字节_显示掩盖较低和较高的16位数字半字节| 8086微处理器...
  9. 论文翻译:Real-Time High-Resolution Background Matting
  10. 图片着色后存储为“JPEG”格式存在明显色差问题解决
  11. 10款神奇的字符图案 词汇云生成工具
  12. UnityShader笔记第三课-MVP矩阵原理-M矩阵
  13. python中国社区-Python中文社区名称的统一
  14. J9数字论:DAO与Web3的联系
  15. [禅悟人生]真知从实践中来
  16. 云计算、社交网络和移动互联网------转自月光博客
  17. Google 释出开源软件漏洞扫描工具 OSV-Scanner​
  18. 高博14讲--第三讲 三维空间刚体运动
  19. 企业应用程序安全的新「守护神」
  20. 同步计数器与异步计数器的区别,以及4040计数器的使用

热门文章

  1. flask模拟集群实现消息队列和简单高并发支持
  2. python爬虫从入门到围城教程_传说中的宇宙神剑武功秘籍:《绝地之路:原力学员手册》...
  3. springboot+网建短信通发送短信
  4. Android 隐藏手机号中间4位
  5. IP地址管理----网段划分,特殊IP地址
  6. SpringCloud 企业级应用实战
  7. vue-cli3.0 使用px2rem 或 postcss-plugin-px2rem
  8. 0欧姆电阻能流过无穷大电流吗
  9. 使用com.lorentzos.swipecards创建Tantan探探,tinder般的翻卡片效果
  10. Visio绘图转.eps矢量图(转换后绝对是矢量图,缩放无失真)原创