HDU 4553 约会安排 (区间合并)【线段树】
<题目链接>
小明虽为屌丝级码农,但非常活跃,女神们常常在小明网上的大段发言后热情回复“呵呵”,所以,小明的最爱就是和女神们约会。与此同时,也有很多基友找他开黑,由于数量实在过于巨大,怎么安排时间便成了小明的一大心事。
我们已知小明一共有T的空闲时间,期间会有很多女神或者基友来找小明。
作为一个操作系统曾经怒考71分的大神,小明想到了一个算法,即“首次适应算法”,根据操作系统课本的描述,就是找一段最靠前的符合要求的连续空间分配给每个请求,由此小明做出了一个决定:
当一个基友来找小明时,小明就根据“首次适应算法”来找一段空闲的时间来和基友约好,如果找到,就说“X,let’s fly”(此处,X为开始时间),否则就说“fly with yourself”;
当女神来找小明时,先使用一次“首次适应算法”,如果没有找到,小明就冒着木叽叽的风险无视所有屌丝基友的约定,再次使用“无视基友首次适应算法”,两次只要有一次找到,就说“X,don’t put my gezi”(此处,X为开始时间),否则就说“wait for me”
当然,我们知道小明不是一个节操负无穷的人,如果和女神约会完,还有剩余时间,他还是会和原来约好的基友去dota的。(举个例子:小西(屌丝)和小明约好在1~5这个时间单位段内打dota,这时候,女神来和小明预约长度为3的时间段,那么最终就是1~3小明去和女神约会,搞定后在4~5和小西打dota)
小明偶尔也会想要学习新知识,此时小明就会把某一个时间区间的所有已经预定的时间全部清空用来学习并且怒吼“I am the hope of chinese chengxuyuan!!”,不过小明一般都是三分钟热度,再有人来预定的话,小明就会按耐不住寂寞把学习新知识的时间分配出去。
Input
输入第一行为CASE,表示有CASE组测试数据;
每组数据以两个整数T,N开始,T代表总共的时间,N表示预约请求的个数;
接着的N行,每行表示一个女神或者基友的预约,“NS QT”代表一个女神来找小明约一段长为QT的时间,“DS QT”则代表一个屌丝的长为QT的请求,当然也有可能是小明想学知识了,“STUDY!! L R”代表清空L~R区间内的所有请求。
[Technical Specification]
1. 1 <= CASE <= 30
2. 1 <= T, N <= 100000
3. 1 <= QT <= 110000
4. 1 <= L <= R <=T
Output
对于每一个case,第一行先输出“Case C:”代表是第几个case,然后N行,每行对应一个请求的结果(参照描述)。
输出样本(可复制此处):
“X,let's fly”,”fly with yourself”,”X,don't put my gezi”,”wait for me”,”I am the hope of chinese chengxuyuan!!”
Sample Input
1
5 6
DS 3
NS 2
NS 4
STUDY!! 1 5
DS 4
NS 2
Sample Output
Case 1:
1,let's fly
4,don't put my gezi
wait for me
I am the hope of chinese chengxuyuan!!
1,let's fly
1,don't put my gezi
解题分析:
由于本题要查询连续区间,所以要用到区间合并,每个点维护三个值,该点对应区间的最长连续长度,最长连续前、后缀长度。并且,本题还涉及一个优先级的概念,因此,建立两个线段树,对这两个线段树进行操作,从而达到模拟优先级的作用,具体实现见代码。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; #define Lson rt<<1,l,mid
#define Rson rt<<1|1,mid+1,r
const int M =1e5+;
int n,q;
int tr[M<<][],llen[M<<][],rlen[M<<][];
int lazy[M<<][]; void Pushup(int rt,int len,int ty){ //区间合并,维护最长连续区间
llen[rt][ty]=llen[rt<<][ty];
rlen[rt][ty]=rlen[rt<<|][ty];
if(llen[rt<<][ty]==(len-(len>>)))llen[rt][ty]+=llen[rt<<|][ty];
if(rlen[rt<<|][ty]==(len>>))rlen[rt][ty]+=rlen[rt<<][ty];
tr[rt][ty]=max(max(tr[rt<<][ty],tr[rt<<|][ty]),rlen[rt<<][ty]+llen[rt<<|][ty]);
}
void Pushdown(int rt,int len,int ty){ //将lazy标记下放
if(lazy[rt][ty]!=-){
int tmp=lazy[rt][ty];
tr[rt<<][ty]=llen[rt<<][ty]=rlen[rt<<][ty]=(len-(len>>))*tmp;
tr[rt<<|][ty]=llen[rt<<|][ty]=rlen[rt<<|][ty]=(len>>)*tmp;
lazy[rt<<][ty]=lazy[rt<<|][ty]=tmp;
lazy[rt][ty]=-;
}
}
void build(int rt,int l,int r,int ty){
lazy[rt][ty]=-;
if(l==r){
tr[rt][ty]=llen[rt][ty]=rlen[rt][ty]=; //值为1代表该点有时间,为0代表没时间
return;
}
int mid=(l+r)>>;
build(Lson,ty);
build(Rson,ty);
Pushup(rt,r-l+,ty);
}
void update(int rt,int l,int r,int L,int R,int c,int ty){
if(L<=l&&r<=R){
lazy[rt][ty]=c;
tr[rt][ty]=llen[rt][ty]=rlen[rt][ty]=(r-l+)*c;
return;
}
Pushdown(rt,r-l+,ty);
int mid=(l+r)>>;
if(L<=mid)update(Lson,L,R,c,ty);
if(R>mid)update(Rson,L,R,c,ty);
Pushup(rt,r-l+,ty);
}
int query(int rt,int l,int r,int len,int ty){ //返回满足连续区间>=len的区间最左值,掌握这种query函数
if(l==r)return l;
Pushdown(rt,r-l+,ty);
int mid=(l+r)>>;
//因为要尽量使符合要求的区间靠前,所以这里按左、中、右的顺序来查询
if(tr[rt<<][ty]>=len)return query(Lson,len,ty);
else if(rlen[rt<<][ty]+llen[rt<<|][ty]>=len)return mid-rlen[rt<<][ty]+; //如果是在左右子区间的后缀、前缀之间,则直接返回左区间的后缀最左值的下标
else return query(Rson,len,ty);
}
int main(){
int T,ncase=;scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&q);
build(,,n,); //基友的请求建一个线段树
build(,,n,); //女神的请求建一颗线段树,更新的时候,根据优先级,对这两个不同的线段树进行操作
char op[];
int x,y;
printf("Case %d:\n", ++ncase);
while(q--){
scanf("%s",op);
if(op[]=='D'){
scanf("%d",&x);
if(tr[][]>=x){ //如果存在>=x的连续区间
int ans=query(,,n,x,); //得到符合要求区间的最左值下标
printf("%d,let's fly\n", ans);
update(,,n,ans,ans+x-,,); //只更新基友树上的时间安排
}
else printf("fly with yourself\n");
}
else if(op[]=='N'){
scanf("%d",&x);
if(tr[][]>=x){ //如果不用占用基友的时间也能与女神约会,即如果优先级低的基友树上也能满足
int ans=query(,,n,x,);
printf("%d,don't put my gezi\n", ans);
update(,,n,ans,ans+x-,,); //基友树上要更新一段
update(,,n,ans,ans+x-,,); //女神树上也要更新同样一段,因为女神的要求之间优先级是相同的,如果有女神占了一段时间,那么其它女神也不能占用
}
else{
if(tr[][]>=x){ //只要女神树上能满足,此时即使基友树上发生冲突也不管,如果需要占用基友时间,直接强制更新,体现了女神的高优先级
int ans=query(,,n,x,);
printf("%d,don't put my gezi\n", ans);
update(,,n,ans,ans+x-,,);
update(,,n,ans,ans+x-,,);
}
else printf("wait for me\n");
}
}
else{
scanf("%d%d", &x, &y);
printf("I am the hope of chinese chengxuyuan!!\n");
update(,,n,x,y,,); //同时将基友树和女神树上的要求全部清除
update(,,n,x,y,,);
}
}
}
return ;
}
2018-10-01
HDU 4553 约会安排 (区间合并)【线段树】的更多相关文章
- HDU 4553 约会安排(线段树区间合并+双重标记)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4553 题目大意:就是有三种操作: ①DS x,安排一段长度为x的空闲时间跟屌丝一起,输出这段时间的起点 ...
- HDU - 4553 约会安排(区间合并)
https://cn.vjudge.net/problem/HDU-4553 Description 寒假来了,又到了小明和女神们约会的季节. 小明虽为屌丝级码农,但非常活跃,女神们常常在小明网上的 ...
- 约会安排---hdu4553(线段树,麻烦的区间覆盖)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4553 算是poj3667的加强版,建立两颗线段树,一个是DS区间,另一个是NS区间.那么根据题意, ...
- hdu 4553 约会安排
约会安排 http://acm.hdu.edu.cn/showproblem.php?pid=4553 Time Limit: 2000/1000 MS (Java/Others) Memory ...
- BZOJ 2243:染色(树链剖分+区间合并线段树)
[SDOI2011]染色Description给定一棵有n个节点的无根树和m个操作,操作有2类:1.将节点a到节点b路径上所有点都染成颜色c:2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认 ...
- HDU 1540 区间合并线段树
题目大意: 就是给定一堆位置,进行删除还原,最后找到 t 位置上的最大连续位置 #include <cstdio> #include <cstring> #include &l ...
- HDU 5029 Relief grain(离线+线段树+启发式合并)(2014 ACM/ICPC Asia Regional Guangzhou Online)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5029 Problem Description The soil is cracking up beca ...
- hdu 5700区间交(线段树)
区间交 Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submiss ...
- hdu 5274 Dylans loves tree(LCA + 线段树)
Dylans loves tree Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Othe ...
随机推荐
- Confluence 6 修改 Home 目录的位置
当 Confluence 第一次启动的时候,Confluence 将会读取 confluence-init.properties 文件并从这个文件中确定如何去查找 Home 目录. 希望修改 home ...
- flask 中orm关系映射 sqlalchemy的查询
flask的orm框架(SQLAlchemy)-一对多查询以及多对多查询 一对多,多对多是什么? 一对多.例如,班级与学生,一个班级对应多个学生,或者多个学生对应一个班级. 多对多.例如,学生与课 ...
- requireJs require.config公共配置
//场景:让require.config配置文件成一个公共文件,每个页面引用这个公共配置 //方式一样例: require.config({ baseUrl: (function () { var p ...
- Data Preprocess
本文试图解决一个问题,即我们自定义的数据如何训练模型?初识深度学习,我们接触手写数字识别模型,但是批次数据是mnist已经定义好的,我们现在有自己的图片如何做成批次进行训练模型. 现在我们将准备好的原 ...
- bzoj 1812
什么鬼noip互测题... 这题很显然是树形dp,但设计状态以及转移是个难点 记状态f[i][j][k]表示以i为根节点的子树,离i最近的祖宗节点编号为j放了虫洞(伐木场?),i的子树内放了k个伐木场 ...
- linux下的抓包
1. 查看网卡名字 cat /proc/net/dev 2.抓取外网进来的包 tcpdump -i eth0 port -s -w .pcap 3.抓取自己服务器上的两个程序之间访问的数据 换成 lo ...
- OpenCV-Python教程8-图像混合
一.图片相加 要叠加两张图片,使用cv2.add(),相加两幅图片的形状(高度.宽度.通道数)必须相同.numpy中可以直接用res = img1 + img2相加.但是两者的结果并不相同 impor ...
- Scrapy项目创建以及目录详情
Scrapy项目创建已经目录详情 一.新建项目(scrapy startproject) 在开始爬取之前,必须创建一个新的Scrapy项目.进入自定义的项目目录中,运行下列命令: PS C:\scra ...
- python--使用队列结构来模拟烫手山芋的游戏
基本功,磨起来. # coding = utf-8 class Queue: def __init__(self): self.items = [] def is_empty(self): retur ...
- [转]编程珠玑第五章二分搜索(折半查找)之java实现
http://blog.csdn.net/hwe_xc/article/details/51813080 二分搜索又称为折半查找,用来高效快速的解决如下问题: 我们需要确定排序后的数组x[0..n-1 ...