Description
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.
Input
* 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
Output
* 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.
Sample Input
10 6 1 3 1 3 1 3 1 3 2 5 5 1 6
Sample Output
1 4 7 0 5
第一次涉及区间合并的题目,多谢玉斌大神的博客。
区间合并最难处理的就是跨区间问题,所求连续区间有可能跨越两个子树,为了解决跨区间问题,引入两个数组lc[],rc[],lc专门保存该区间从最左端点开始的连续量,rc保存从最右端点开始的连续量。。记住一定是记录从两个端点开始的连续,mc[]就是保存当前的最大连续量,因此判断的时候
mc[root]=max(mc[Lson],mc[Rson]);首先分别从两个子树中间取得最大量
mc[root]=max(mc[root],lc[Rson]+rc[Lson]) 为了计算跨区间连续,则比较下lc右子树+rc左子树和当前值,所以知道为什么要从区间端点开始计算起吧。
玉斌大神用了染色的技巧,使得占用和空出房间都很方便的调用一个函数、、还有懒惰标记,也需要一点点技巧
很郁闷的是,我自认为把线段树的区间合并应该弄得挺熟练了,结果碰到HDU 3308 和3397,愣是WA的不明不白。。。尤其是3308,这么简单的题目,我WA之后找了网上一个思路跟我一模一样的代码,然后它的居然A掉了,我在作死的找BUG,两份代码几乎一样,我就算参照起来,改自己的代码,差点连变量名都想改成一样的了。。但就是WA。。。我就郁闷死了
线段树看来得先放一放。。除非我先A掉HDU那两题。。。主要是找BUG。。真的WA的不明不白,我搜了N多博客。思路都是这样。。我左改右改就是通不过。
#include <iostream> #include <cstdio> #include <cstring> #define maxn 50006 #define Lson (x<<1),l,mid #define Rson (x<<1|1),mid+1,r #define INF 10000005 using namespace std; int flag[maxn<<3]; int lc[maxn<<3]; int rc[maxn<<3]; int mc[maxn<<3]; int max(int a,int b) { return a>b?a:b; } void build(int x,int l,int r) { flag[x]=-1; lc[x]=rc[x]=mc[x]=r-l+1; if (l==r) { return; } int mid=(l+r)/2; build(Lson); build(Rson); } void pushdown(int x,int l,int r) { if (flag[x]!=-1) { int mid=(l+r)/2; flag[x<<1]=flag[x<<1|1]=flag[x]; mc[x<<1]=lc[x<<1]=rc[x<<1]= flag[x]? 0:mid-l+1; mc[x<<1|1]=lc[x<<1|1]=rc[x<<1|1]=flag[x]? 0:r-mid; flag[x]=-1; } } int search(int a,int x,int l,int r) { if(l==r) return l; pushdown(x,l,r); int mid=(l+r)/2; if (mc[x<<1]>=a) return search(a,Lson); else if (rc[x<<1]+lc[x<<1|1]>=a) { return mid-rc[x<<1]+1; } else return search(a,Rson); } void update(int x,int l,int r) { int mid=(l+r)/2; mc[x]=max(mc[x<<1],mc[x<<1|1]); mc[x]=max(mc[x],lc[x<<1|1]+rc[x<<1]); lc[x]=lc[x<<1]+ (lc[x<<1]==mid-l+1? lc[x<<1|1]:0); rc[x]=rc[x<<1|1]+(rc[x<<1|1]==r-mid? rc[x<<1]:0); } void color(int L,int R,int c,int x,int l,int r) { if (L<=l&&r<=R) { flag[x]=c; mc[x]=lc[x]=rc[x]=c?0:r-l+1; return; } pushdown(x,l,r); int mid=(l+r)/2; if (L<=mid) color(L,R,c,Lson); if (R>mid) color(L,R,c,Rson); update(x,l,r); } int main() { int n,m; while (scanf("%d %d",&n,&m)!=EOF) { build(1,1,n); int i,j; for (i=1;i<=m;i++) { int a,b,c; scanf("%d",&a); if (a==1) { scanf("%d",&b); if (mc[1]<b) puts("0"); else { int ans=search(b,1,1,n); printf("%d ",ans); color(ans,ans+b-1,1,1,1,n); } } else { scanf("%d %d",&b,&c); color(b,b+c-1,0,1,1,n); } } } return 0; }