POJ 3667 线段树的区间合并简单问题
题目大意:
有一排标号1-N的房间。
操作一:询问是不是有连续长度为a的空房间,有的话住进最左边(占用a个房间)
操作二:将[a,a+b-1]的房间清空(腾出b个房间)
思路:记录每个区间中“靠左”“靠右”“中间”的空房间
线段树操作:update:区间替换
query:询问满足条件的最左端点
题目链接:
http://vjudge.net/problem/viewProblem.action?id=10354
题目操作:
因为这里找从最左边住起的房间,所以这里不能像常规地写query函数那样写了,终于发现自己只会套模板的下场的悲哀了,智商拙计啊T T
而且你在query函数,因为要尽可能找左边的房间,所以要从左边先递归
1.
int query(int cur,int x,int y,int w)
{
int mid=(x+y)>>1,ls=cur<<1,rs=cur<<1|1;
if(x==y) return x; //这里是表示找到树的底层无叶节点了就结束函数,同时也防止找不到点,其实这里如果找不到所求点的话,会不断进入右子树最后抵达最大的子节点返回
pushdown(cur,x,y);
if(mc[cur<<1]>=w) return query(ls,x,mid,w); //如果左侧能找到满足的点,我们不断朝左侧进行递归
else if(rc[cur<<1]+lc[cur<<1|1]>=w) return mid-rc[cur<<1]+1;//左侧不成立我们在开始找中间并在一起形成的房间的最左侧点
return query(rs,mid+1,y,w); //左侧中间都不成立,那么只能进入右子树进行找点
}
因为这个query函数必然有返回值,所以,我们在主函数中必须先进行判断能否找到适合的一连串的房间,然后再进行ans=query(1,1,n,w)操作以及后面的房间入住的覆盖操作。
这个判断很简单 1为线段树根节点,所以mc[1]其实是最大的连续最长房间,if(mc[1]>=w)这个判断执行就可以了
这里介绍一下puts("0"):
puts()函数用来向标准输出设备(屏幕)写字符串并换行,其调用方式为,puts(s);其中s为字符串字符(字符串数组名或字符串指针)。
所以这道题puts("0");就输出了不存在的情况
2.
当然我也可以换种方式在query的函数里面进行一下小小的修改,使得它在不能找到房间的时候输出-1;
int query(int cur,int x,int y,int w)
{
int mid=(x+y)>>1,ls=cur<<1,rs=cur<<1|1;
if(x==y) return mc[cur]<w?-:x; //在这修改一下,然后直接在main函数中判断为-1,那么输出0即可
pushdown(cur,x,y);
if(mc[cur<<1]>=w) return query(ls,x,mid,w);
else if(rc[cur<<1]+lc[cur<<1|1]>=w) return mid-rc[cur<<1]+1;
return query(rs,mid+1,y,w);
}
总代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 50010
#define L ls,x,mid
#define R rs,mid+1,y
int rev[N<<],lc[N<<],rc[N<<],mc[N<<];
void update(int cur,int x,int y)
{
int mid=(x+y)/,ls=cur<<,rs=cur<<|;
lc[cur]=lc[ls],rc[cur]=rc[rs];
mc[cur]=max(mc[ls],mc[rs]);
mc[cur]=max(mc[cur],rc[ls]+lc[rs]);
if(lc[ls]==mid-x+) lc[cur]=lc[ls]+lc[rs];
if(rc[rs]==y-mid) rc[cur]=rc[rs]+rc[ls];
}
void build(int cur,int x,int y)
{
int mid=(x+y)/,ls=cur<<,rs=cur<<|;
rev[cur]=-;
if(x==y){
lc[cur]=rc[cur]=mc[cur]=;
return;
}
build(ls,x,mid);
build(rs,mid+,y);
update(cur,x,y);
}
void pushdown(int cur,int x,int y)
{
int mid=(x+y)/,ls=cur<<,rs=cur<<|;
if(rev[cur]!=-){
if(rev[cur]==){
rev[ls]=rev[rs]=;
lc[ls]=rc[ls]=mc[ls]=lc[rs]=rc[rs]=mc[rs]=;
rev[cur]=-;
}
else if(rev[cur]==){
rev[ls]=rev[rs]=;
lc[ls]=rc[ls]=mc[ls]=mid-x+;
lc[rs]=rc[rs]=mc[rs]=y-mid;
rev[cur]=-;
}
}
}
void change(int cur,int x,int y,int s,int t,int v)
{
int mid=(x+y)/,ls=cur<<,rs=cur<<|;
if(x>=s&&y<=t){
rev[cur]=v;
lc[cur]=rc[cur]=mc[cur]=v?:y-x+;
return;
}
pushdown(cur,x,y);
if(mid>=s) change(ls,x,mid,s,t,v);
if(mid+<=t) change(rs,mid+,y,s,t,v);
update(cur,x,y);
}
int query(int cur,int x,int y,int w)
{
int mid=(x+y)>>,ls=cur<<,rs=cur<<|;
if(x==y) return x;
pushdown(cur,x,y);
if(mc[cur<<]>=w) return query(ls,x,mid,w);
else if(rc[cur<<]+lc[cur<<|]>=w) return mid-rc[cur<<]+;
return query(rs,mid+,y,w);
}
int main()
{
int n,m,op,a,b;
while(scanf("%d%d",&n,&m)!=EOF){
build(,,n);
for(int i=;i<m;i++){
scanf("%d",&op);
if(op==){
scanf("%d",&a);
if(mc[]<a) puts("");
else{
int ans=query(,,n,a);
printf("%d\n",ans);
change(,,n,ans,ans+a-,);
}
}
else{
scanf("%d%d",&a,&b);
change(,,n,a,a+b-,);
}
}
}
return ;
}
POJ 3667 线段树的区间合并简单问题的更多相关文章
- POJ 3667 线段树区间合并裸题
题意:给一个n和m,表示n个房间,m次操作,操作类型有2种,一种把求连续未租出的房间数有d个的最小的最左边的房间号,另一个操作时把从x到x+d-1的房间号收回. 建立线段树,值为1表示未租出,0为租出 ...
- 线段树的区间合并 B - LCIS
B - LCIS HDU - 3308 这个是一个很简单很明显的线段树的区间合并,不过区间合并的题目都还是有点难写,建议存个板子. #include <cstdio> #include & ...
- 线段树:CDOJ1592-An easy problem B (线段树的区间合并)
An easy problem B Time Limit: 2000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) Pr ...
- CodeForces - 587E[线段树+线性基+差分] ->(线段树维护区间合并线性基)
题意:给你一个数组,有两种操作,一种区间xor一个值,一个是查询区间xor的结果的种类数 做法一:对于一个给定的区间,我们可以通过求解线性基的方式求出结果的种类数,而现在只不过将其放在线树上维护区间线 ...
- Codeforces Round #222 (Div. 1) D. Developing Game 线段树有效区间合并
D. Developing Game Pavel is going to make a game of his dream. However, he knows that he can't mak ...
- POJ 3667 & HDU 3308 & HDU 3397 线段树的区间合并
看到讲课安排上 线段树有一节课"区间合并" 我是迷茫的 因为并没有见过 然后了解了一下题目 发现以前写过 还是很麻烦的树链剖分 大概是 解决带修改的区间查询"连续问题&q ...
- POJ 3667 线段树区间合并
http://www.cnblogs.com/scau20110726/archive/2013/05/07/3065418.html 用线段树,首先要定义好线段树的节点信息,一般看到一个问题,很难很 ...
- POJ 2750 Potted Flower(线段树的区间合并)
点我看题目链接 题意 : 很多花盆组成的圆圈,每个花盆都有一个值,给你两个数a,b代表a位置原来的数换成b,然后让你从圈里找出连续的各花盆之和,要求最大的. 思路 :这个题比较那啥,差不多可以用DP的 ...
- HDU_3308_线段树_区间合并
LCIS Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...
随机推荐
- Vijos p1688 病毒传递 树形DP
https://vijos.org/p/1688 看了下别人讨论的题解才想到的,不过方法和他的不同,感觉它的是错的.(感觉.感觉) 首先N只有1000, 如果能做到暴力枚举每一个节点,然后O(N)算出 ...
- C. Bear and Colors 区间枚举的技巧
http://codeforces.com/problemset/problem/673/C 先说一个枚举区间的技巧,枚举前缀,不要枚举后缀. 就是下面这个代码是不好的 ; i <= n; ++ ...
- 配置组件的 props
组件是相互独立.可复用的单元,一个组件可能在不同地方被用到.但是在不同的场景下对这个组件的需求可能会根据情况有所不同,例如一个点赞按钮组件,在我这里需要它显示的文本是“点赞”和“取消”,当别的同事拿过 ...
- C#中构造函数和析构函数区别
把对象的初始化工作放在构造函数中,把清除工作放在析构函数中.当对象被创建时,构造函数被自动执行.当对象消亡时,析构函数被自动执行.这样就不用担心忘记对象的初始化和清除工作. 析构函数是由垃圾回收器控制 ...
- java 自定义注解,并使用示例
场景: 对需要校验 手机验证码和短信验证码的controller方法添加 自定义的注解 @CheckType 1. 定义注解 /** * 需要短信.验证码验证方法上的注解 * date: 2018年 ...
- idea DeBug调试学习
在Intellij IDEA中使用Debug 目录 一.Debug开篇 二.基本用法&快捷键 三.变量查看 四.计算表达式 五.智能步入 六.断点条件设置 七.多线程调试 八.回退断点 九.中 ...
- NIO客户端主要创建过程
NIO客户端主要创建过程: 步骤一:打开SocketChannel,绑定客户端本地地址(可选,默认系统会随机分配一个可用的本地地址),示例代码如下: SocketChannel client ...
- AJPFX关于部分String类方法
string类使用于描述字符串事物常见的操作:1.获取: 1.1 字符串中的包含的字符数,也就是字符串的长度 int length():获取字符串的长度 1.2 根据位置获取位置上的某 ...
- checkbox:click事件触发span元素内容改变
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 搜索模板elasticsearch
搜索: like 对中文分词效率与支持都不太友好elasticsearch 实时的(效率高).分布式(可扩展)的搜索和分析引擎,基于Lucene全文搜索引擎工具包,算法基于倒排索引算法(eg:一篇文章 ...