Problem Description
寒假来了,又到了小明和女神们约会的季节。
小明虽为屌丝级码农,但非常活跃,女神们常常在小明网上的大段发言后热情回复“呵呵”,所以,小明的最爱就是和女神们约会。与此同时,也有很多基友找他开黑,由于数量实在过于巨大,怎么安排时间便成了小明的一大心事。
我们已知小明一共有T的空闲时间,期间会有很多女神或者基友来找小明。
作为一个操作系统曾经怒考71分的大神,小明想到了一个算法,即“首次适应算法”,根据操作系统课本的描述,就是找一段最靠前的符合要求的连续空间分配给每个请求,由此小明做出了一个决定:
当一个基友来找小明时,小明就根据“首次适应算法”来找一段空闲的时间来和基友约好,如果找到,就说“X,let’s fly”(此处,X为开始时间),否则就说“fly with yourself”;
当女神来找小明时,先使用一次“首次适应算法”,如果没有找到,小明就冒着木叽叽的风险无视所有屌丝基友的约定,再次使用“无视基友首次适应算法”,两次只要有一次找到,就说“X,don’t put my gezi”(此处,X为开始时间),否则就说“wait for me”
当然,我们知道小明不是一个节操负无穷的人,如果和女神约会完,还有剩余时间,他还是会和原来约好的基友去dota的。(举个例子:小西(屌丝)和小明约好在15这个时间单位段内打dota,这时候,女神来和小明预约长度为3的时间段,那么最终就是13小明去和女神约会,搞定后在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区间内的所有请求。
- 1 <= CASE <= 30
- 1 <= T, N <= 100000
- 1 <= QT <= 110000
- 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
**** 思路
线段树维护最长连续子序列 + 优先级处理。题意好像很明了但是很难处理这些复杂的信息,需要用到两颗线段树维护。一棵属于屌丝的,一棵属于女神的。女神的线段树只能女神更新和学习更新,但是屌丝的线段树 屌丝可以更新,女神可以更新,学习也可以更新。
-
屌丝朋友打游戏那么就去屌丝的线段树里找有没有符合的区间如果有去查询左端点。否则就是没有满足的区间。
-
女神约会先去屌丝的线段树里找有没有符合的区间如果有查左端点没有就去女神的线段树里找有没有符合的区间。只要找到一次就符合,否则就是没有满足的区间。
-
至于小明要学习直接同时更新两棵线段树把时间归位即可。
-
其余的操作和1540那个题差不多都是维护最长连续子序列的模板,注意细节即可。
坑点,查询左端点的时候,查询右区间的必须写在查询跨越左右区间的后面,否则可能导致右区间有足够的长度满足当前时间长度导致答案错误,WA了12发。血的教训。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define lson k<<1,l,m
#define rson k<<1|1,m+1,r
using namespace std;
const int maxn = 100050;
struct node{
int ls; //以左端点开始的连续
int rs; //以右端点终点的连续
int ms; //最大连续
}s[maxn<<2],t[maxn<<2]; //s表示女神,t表示屌丝
int lazy[maxn<<2];
inline void push_up(int k,int l,int r)
{
int m = (l + r) >> 1;
s[k].ls = s[k<<1].ls;
s[k].rs = s[k<<1|1].rs;
s[k].ms = max(max(s[k<<1].ms,s[k<<1|1].ms),s[k<<1].rs+s[k<<1|1].ls);
if(s[k<<1].ms == m-l+1){
s[k].ls += s[k<<1|1].ls;
}
if(s[k<<1|1].ms == r-m){
s[k].rs += s[k<<1].rs;
}
t[k].ls = t[k<<1].ls;
t[k].rs = t[k<<1|1].rs;
t[k].ms = max(max(t[k<<1].ms,t[k<<1|1].ms),t[k<<1].rs+t[k<<1|1].ls);
if(t[k<<1].ms == m-l+1){
t[k].ls += t[k<<1|1].ls;
}
if(t[k<<1|1].ms == r-m){
t[k].rs += t[k<<1].rs;
}
}
inline void push_down(int k,int l,int r)
{
int m = (l + r) >> 1;
if(t[k].ms == r-l+1){
t[k<<1].ms = t[k<<1].ls = t[k<<1].rs = m-l+1;
t[k<<1|1].ms = t[k<<1|1].ls = t[k<<1|1].rs = r-m;
}
else if(t[k].ms == 0){
t[k<<1].ms = t[k<<1].ls = t[k<<1].rs = 0;
t[k<<1|1].ms = t[k<<1|1].ls = t[k<<1|1].rs = 0;
}
if(s[k].ms == r-l+1){
s[k<<1].ms = s[k<<1].ls = s[k<<1].rs = m-l+1;
s[k<<1|1].ms = s[k<<1|1].ls = s[k<<1|1].rs = r-m;
}
else if(s[k].ms == 0){
s[k<<1].ms = s[k<<1].ls = s[k<<1].rs = 0;
s[k<<1|1].ms = s[k<<1|1].ls = s[k<<1|1].rs = 0;
}
}
inline void build(int k,int l,int r)
{
s[k].ls = s[k].rs = s[k].ms = r-l+1;
t[k].ls = t[k].rs = t[k].ms = r-l+1;
if(l == r){
return ;
}
int m = (l + r) >> 1;
build(lson);
build(rson);
push_up(k,l,r);
}
inline void update(int k,int l,int r,int ql,int qr,int op)
{
if(qr < l || r < ql){
return ;
}
if(ql <= l && r <= qr){
if(op == 1){
t[k].ls = t[k].rs = t[k].ms = 0;
}
if(op == 2){
s[k].ls = s[k].rs = s[k].ms = 0;
t[k].ls = t[k].rs = t[k].ms = 0;
}
if(op == 3){
s[k].ls = s[k].rs = s[k].ms = r-l+1;
t[k].ls = t[k].rs = t[k].ms = r-l+1;
}
return ;
}
int m = (l + r) >> 1;
push_down(k,l,r);
update(lson,ql,qr,op);
update(rson,ql,qr,op);
push_up(k,l,r);
}
int query(int k,int l,int r,int op,int ans)
{
if(l == r){
if(op == 1){
return t[k].ls;
}
else{
return s[k].ls;
}
}
push_down(k,l,r);
int m = (l + r) >> 1;
if(op == 1){
if(t[k<<1].ms >= ans){ //在左区间
return query(lson,op,ans);
}
else if(t[k<<1].rs + t[k<<1|1].ls >= ans){ //跨越左右,必须先写这个在写查询右边的
return m - t[k<<1].rs + 1;
}
else{ //在右区间
return query(rson,op,ans);
}
}
if(op == 2){
if(s[k<<1].ms >= ans){ //在左区间
return query(lson,op,ans);
}
else if(s[k<<1].rs + s[k<<1|1].ls >= ans){ //跨越左右,必须先写这个在写查询右边的
return m - s[k<<1].rs + 1;
}
else{ //右区间
return query(rson,op,ans);
}
}
}
int main()
{
int T,n,m;
scanf("%d",&T);
for(int k = 1;k <= T;k++){
scanf("%d%d",&n,&m);
memset(lazy,0,sizeof(lazy));
build(1,1,n);
printf("Case %d:\n",k);
char op[10];
int x,y,l,r;
while(m--){
scanf("%s%d",op,&x);
if(op[0] == 'D'){ //屌丝
if(t[1].ms >= x){
l = query(1,1,n,1,x); //左端点
r = l + x - 1; //右端点
printf("%d,let's fly\n",l);
update(1,1,n,l,r,1); //只更新屌丝的线段树
}
else{
printf("fly with yourself\n");
}
}
else if(op[0] == 'N'){ //女神
if(t[1].ms >= x){
l = query(1,1,n,1,x);
r = l + x - 1;
printf("%d,don't put my gezi\n",l);
update(1,1,n,l,r,2); //更新屌丝 和 女神的线段树
}
else if(s[1].ms >= x){
l = query(1,1,n,2,x);
r = l + x - 1;
printf("%d,don't put my gezi\n",l);
update(1,1,n,l,r,2); //更新屌丝 和 女神的线段树
}
else{
printf("wait for me\n");
}
}
else{ //学习
scanf("%d",&y);
printf("I am the hope of chinese chengxuyuan!!\n");
update(1,1,n,x,y,3);
}
}
}
return 0;
}
愿你走出半生,归来仍是少年~