P2894 [USACO08FEB]酒店Hotel
漂亮小姐姐点击就送:https://www.luogu.org/problemnew/show/P2894
题目描述
The cows are journeying north to Thunder Bay in Canada to gain cultural enrichment and enjoy a vacation on the sunny shores of Lake Superior. Bessie, ever the competent travel agent, has named the Bullmoose Hotel on famed Cumberland Street as their vacation residence. This immense hotel has N (1 ≤ N ≤ 50,000) rooms all located on the same side of an extremely long hallway (all the better to see the lake, of course).
The cows and other visitors arrive in groups of size Di (1 ≤ Di ≤ N) and approach the front desk to check in. Each group i requests a set of Di contiguous rooms from Canmuu, the moose staffing the counter. He assigns them some set of consecutive room numbers r..r+Di-1 if they are available or, if no contiguous set of rooms is available, politely suggests alternate lodging. Canmuu always chooses the value of r to be the smallest possible.
Visitors also depart the hotel from groups of contiguous rooms. Checkout i has the parameters Xi and Di which specify the vacating of rooms Xi ..Xi +Di-1 (1 ≤ Xi ≤ N-Di+1). Some (or all) of those rooms might be empty before the checkout.
Your job is to assist Canmuu by processing M (1 ≤ M < 50,000) checkin/checkout requests. The hotel is initially unoccupied.
参考样例,第一行输入n,m ,n代表有n个房间,编号为1---n,开始都为空房,m表示以下有m行操作,以下 每行先输入一个数 i ,表示一种操作:
若i为1,表示查询房间,再输入一个数x,表示在1--n 房间中找到长度为x的连续空房,输出连续x个房间中左端的房间号,尽量让这个房间号最小,若找不到长度为x的连续空房,输出0。
若i为2,表示退房,再输入两个数 x,y 代表 房间号 x---x+y-1 退房,即让房间为空。
输入输出格式
输入格式:
* Line 1: Two space-separated integers: N and M
* Lines 2..M+1: Line i+1 contains request expressed as one of two possible formats: (a) Two space separated integers representing a check-in request: 1 and Di (b) Three space-separated integers representing a check-out: 2, Xi, and Di
输出格式:
* Lines 1.....: For each check-in request, output a single line with a single integer r, the first room in the contiguous sequence of rooms to be occupied. If the request cannot be satisfied, output 0.
输入输出样例
10 6 1 3 1 3 1 3 1 3 2 5 5 1 6
1 4 7 0 5
//来让我们A掉 P2894 [USACO08FEB]酒店Hotel 吧 //记录每个节点向左延伸和向右延伸的最大长度以及它的区间内最长的连续为0的长度 //这题lazy标记可以直接覆盖 //给写混了。。。动态开点写了root<<1和root<<1|1 //除了第一个点都MLE.......炸掉了 //。。9:50__发现了错误所在:pushdown的时候忘了把root的标记消掉。。。。 //..........现在是除了第一个点都WA掉了 //在第二个数据第718行出现第一个错误点 //query(tree[root].lson,tree[tree[root].lson].rto); //在if里加上tree[tree[root].lson].rto>0再执行这句不知道为啥不对。。 //知道为啥在query里这样写会错了。。。。 //因为这样写,进了左儿子之后就不能保证它是和右儿子连续的了。。。。 //我个zz啊。。。。 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; const int N=5e4+5; int n,m,Ans; struct NODE { int lson,rson; int l,r,mid,len; int maxs; int lto,rto; int mark; //1为入住,2为退房 }tree[N<<2]; int now_node,Root; inline int read() { char c=getchar();int num=0; for(;!isdigit(c);c=getchar()); for(;isdigit(c);c=getchar()) num=num*10+c-'0'; return num; } void build(int &root,int l,int r) { root=++now_node; tree[root].l=l,tree[root].r=r,tree[root].mid=l+r>>1; tree[root].len=tree[root].lto=tree[root].rto=tree[root].maxs=r-l+1; if(l==r) return; build(tree[root].lson,l,tree[root].mid); build(tree[root].rson,tree[root].mid+1,r); } inline void pushup(const int &root) { if(tree[tree[root].lson].len==tree[tree[root].lson].maxs) //整个左儿子全是空的 tree[root].lto=tree[tree[root].lson].len+tree[tree[root].rson].lto; else tree[root].lto=tree[tree[root].lson].lto; if(tree[tree[root].rson].len==tree[tree[root].rson].maxs) //右儿子全是空的 tree[root].rto=tree[tree[root].rson].len+tree[tree[root].lson].rto; else tree[root].rto=tree[tree[root].rson].rto; tree[root].maxs=max(tree[tree[root].lson].maxs,tree[tree[root].rson].maxs); //左右儿子最长值 tree[root].maxs=max(tree[root].maxs,tree[tree[root].lson].rto+tree[tree[root].rson].lto); //左右儿子拼合 } inline void pushdown(const int &root) { if(tree[root].mark==0) return; if(tree[root].mark==1) { tree[tree[root].lson].lto=tree[tree[root].lson].rto=tree[tree[root].lson].maxs=0; tree[tree[root].rson].lto=tree[tree[root].rson].rto=tree[tree[root].rson].maxs=0; tree[tree[root].lson].mark=1; tree[tree[root].rson].mark=1; } else { tree[tree[root].lson].lto=tree[tree[root].lson].rto=tree[tree[root].lson].maxs=tree[tree[root].lson].len; tree[tree[root].rson].lto=tree[tree[root].rson].rto=tree[tree[root].rson].maxs=tree[tree[root].rson].len; tree[tree[root].lson].mark=2; tree[tree[root].rson].mark=2; } tree[root].mark=0; //忘写了qwq mmp } void query(const int &root,int x) //查询左端点 { if(tree[root].len==x) //找到了长度为x的连续空房 { Ans=tree[root].l; return; } pushdown(root); if(tree[tree[root].lson].maxs>=x) //左儿子里有足够的空房,去左儿子里找左端点 query(tree[root].lson,x); else if(tree[tree[root].lson].rto+tree[tree[root].rson].lto>=x) //左儿子和右儿子拼起来够,去左儿子里找左端点 { Ans=tree[root].mid-tree[tree[root].lson].rto+1; return; } else //只能去右儿子找了,而且一定能找到 query(tree[root].rson,x); } void modify(const int &root,int l,int r,bool flag) //0入住/1退房 { if(tree[root].l==l&&tree[root].r==r) { if(!flag) { tree[root].mark=1; tree[root].lto=tree[root].rto=tree[root].maxs=0; } else { tree[root].mark=2; tree[root].lto=tree[root].rto=tree[root].maxs=tree[root].len; } return; } pushdown(root); if(r<=tree[root].mid) modify(tree[root].lson,l,r,flag); else if(l>tree[root].mid) modify(tree[root].rson,l,r,flag); else { modify(tree[root].lson,l,tree[root].mid,flag); modify(tree[root].rson,tree[root].mid+1,r,flag); } pushup(root); } int main() { // freopen("testdata.in","r",stdin); // freopen("233.out","w",stdout); n=read(),m=read(); build(Root,1,n); for(int i=1,opt,l,r,x;i<=m;++i) { opt=read(); if(opt==1) { x=read(); if(tree[Root].maxs<x) //连续空房不够 { puts("0"); continue; } query(Root,x); printf("%d\n",Ans); modify(Root,Ans,Ans+x-1,0); } else { l=read(),r=read(); modify(Root,l,l+r-1,1); } } return 0; }