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区间内的所有请求。
[Technical Specification]
- 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!!”
source
思路
线段树结点存储的信息为:当前区间最大空闲时间段,最长靠左空闲时间段,最长靠右时间段。具体实现详见代码。
女神和屌丝分开处理,相当于两棵树。屌丝只能在屌丝树上查询更新;女神需要在两棵树上都进行更新。
这里实现查询的时候,pushdown和pushup放在哪里让我很纠结。后来想清楚了,由于查询需要路径上每个结点更新后的信息,所以在判断进入子节点之前需要pushup;然而pushup要保证子节点也要更新,所以pushdown要在pushup之前。
在ac前因为在处理女神的请求的时候忘记同时更新两棵树,只更新了女神树,wa了好久。粗心大意害人不浅啊。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <map>
#include <vector>
using namespace std;
#define endl '
'
typedef long long ll;
const int N = 200000;
struct node {
int mxlen;
int mxl, mxr;
};
struct tnode {
node loser, kami;
};
int lazy[N << 2][2];
tnode st[N << 2];
void pushup(node & p, node & lc, node & rc, int l, int r) {
int len = r - l + 1;
int llen = (len + 1) >> 1, rlen = len >> 1;
p.mxl = lc.mxl + (lc.mxl == llen ? rc.mxl : 0);
p.mxr = rc.mxr + (rc.mxr == rlen ? lc.mxr : 0);
p.mxlen = max(lc.mxlen, rc.mxlen);
p.mxlen = max(p.mxlen, lc.mxr + rc.mxl);
}
void init(int rt, int l, int r, int type) {
if(type) pushup(st[rt].kami, st[rt << 1].kami, st[rt << 1 | 1].kami, l, r);
else pushup(st[rt].loser, st[rt << 1].loser, st[rt << 1 | 1].loser, l, r);
}
void pushdown(node & lc, node & rc, int l, int r, int type, int rt) {
if(lazy[rt][type] > 0) {
lc.mxlen = lc.mxl = lc.mxr = 0;
rc.mxlen = rc.mxl = rc.mxr = 0;
} else if(lazy[rt][type] < 0) {
int len = r - l + 1;
int llen = (len + 1) >> 1, rlen = len >> 1;
lc.mxlen = lc.mxl = lc.mxr = llen;
rc.mxlen = rc.mxl = rc.mxr = rlen;
} else return ;
lazy[rt << 1][type] = lazy[rt][type];
lazy[rt << 1 | 1][type] = lazy[rt][type];
lazy[rt][type] = 0;
}
void build(int l, int r, int rt) {
if(l == r) {
lazy[rt][0] = lazy[rt][1] = 0;
st[rt].loser.mxl = st[rt].loser.mxr = st[rt].loser.mxlen = 1;
st[rt].kami.mxl = st[rt].kami.mxr = st[rt].kami.mxlen = 1;
} else {
lazy[rt][0] = lazy[rt][1] = 0;
st[rt].loser.mxl = st[rt].loser.mxr = st[rt].loser.mxlen = 0;
st[rt].kami.mxl = st[rt].kami.mxr = st[rt].kami.mxlen = 0;
int mid = (l + r) / 2;
build(l, mid, rt << 1);
build(mid + 1, r, rt << 1 | 1);
init(rt, l, r, 0);
init(rt, l, r, 1);
}
}
void update(int l, int r, int p, int len, int val, int type, int rt) { //type 0屌丝 1女神
int L = p, R = p + len - 1;
node * ptr = type ? &st[rt].kami : &st[rt].loser; //根据type动态绑定女神或屌丝的树结点
node * plc = type ? &st[rt << 1].kami : &st[rt << 1].loser;
node * prc = type ? &st[rt << 1 | 1].kami : &st[rt << 1 | 1].loser;
node & cur = *ptr;
node & lc = *plc;
node & rc = *prc;
if(L <= l && R >= r) {
lazy[rt][type] = val;
if(lazy[rt][type] > 0) cur.mxl = cur.mxr = cur.mxlen = 0;
else if(lazy[rt][type] < 0)cur.mxl = cur.mxr = cur.mxlen = r - l + 1;
} else {
int mid = (l + r) / 2;
pushdown(lc, rc, l, r, type, rt);
if(mid >= L) update(l, mid, p, len, val, type, rt << 1);
if(mid < R) update(mid + 1, r, p, len, val, type, rt << 1 | 1);
pushup(cur, lc, rc, l, r);
}
}
int query(int l, int r, int len, int type, int rt) {
if(l == r) return l;
node * ptr = type ? &st[rt].kami : &st[rt].loser;
node * plc = type ? &st[rt << 1].kami : &st[rt << 1].loser;
node * prc = type ? &st[rt << 1 | 1].kami : &st[rt << 1 | 1].loser;
node & cur = *ptr;
node & lc = *plc;
node & rc = *prc;
int mid = (l + r) / 2;
int p;
pushdown(lc, rc, l, r, type, rt);
pushup(cur, lc, rc, l, r);
if(len > cur.mxlen) return 0;
if(len <= lc.mxlen) p = query(l, mid, len, type, rt << 1);
else if(lc.mxr > 0 && len <= lc.mxr + rc.mxl) p = mid - lc.mxr + 1;
else p = query(mid + 1, r, len, type, rt << 1 | 1);
return p;
}
char req[100];
int main() {
int t;
int cases = 0;
scanf("%d", &t);
while(t--) {
cases++;
int n, m;
scanf("%d %d", &n, &m);
printf("Case %d:
", cases);
build(1, n, 1);
while(m--) {
scanf("%s", req);
int len, l, r;
if(req[0] == 'N') {
scanf("%d", &len);
int x = query(1, n, len, 0, 1);
if(x) {
update(1, n, x, len, 1, 0, 1);
update(1, n, x, len, 1, 1, 1);
printf("%d,don't put my gezi
", x);
} else {
x = query(1, n, len, 1, 1);
if(x) {
update(1, n, x, len, 1, 0, 1);
update(1, n, x, len, 1, 1, 1);
printf("%d,don't put my gezi
", x);
} else {
printf("wait for me
");
}
}
} else if(req[0] == 'D') {
scanf("%d", &len);
int x = query(1, n, len, 0, 1);
if(x) {
update(1, n, x, len, 1, 0, 1);
printf("%d,let's fly
", x);
} else {
printf("fly with yourself
");
}
} else {
scanf("%d %d", &l, &r);
update(1, n, l, r - l + 1, -1, 0, 1);
update(1, n, l, r - l + 1, -1, 1, 1);
printf("I am the hope of chinese chengxuyuan!!
");
}
}
}
}