[BZOJ1593]Hotel旅馆

样例
样例输入
10 6
1 3
1 3
1 3
1 3
2 5 5
1 6

样例输出
1
4
7
0
5

一开始看到题,暴力分块来着,结果打完发现自己打了个假分块[哭][哭][哭],已经废到了分块都打不成[颓],结果,题解是个线段树,本来觉得自己线段树学的算是凑合的了,但是板子和脑子还是硬伤,什么线段树,树状数组吧啦吧啦的烂七八糟的板子还是得多打多看,要不撑不到联赛就忘没了(想不到正解打不出板子也是没谁了),言归正传,这基本上就是个稍微变了变形的纯模板题,就是把线段树用的结构体里的变量含义换了换,其实线段树每个函数,基本上都是一个递归的函数。

先说结构体,四个变量,此区间左端点向右最多连续空房间数,此区间右端点向左最多连续空房间数(可能可以左边一部分加上右边一部分编号靠前可满足连续n个房间),此区间内最多连续空房间数(可能一整个区间中的部分房间即可满足),此区间内各房间状态(相当于一个懒标记需要在每次操作查询前不断进行下传-1:没状态<不操作>0:空1:满)。

线段树的几个操作:

(1)建树:还是递归,正常建就行,子节点所有的长度都是1,所有的懒标记均为-1,记得return,所有查到叶子节点后要结束的都需要return掉,不然函数跳不出来,血淋淋的教训[可怕]

(2)入住:查询连续区间(那个z==y return 1对我来说是个谜),查询函数里包含4个变量,父节点区间的左右端点以及要查询的连续区间长度,根据题意查询顺序是左子树,左子树一部分加右子树,最后是右子树,然后递归查就行了,记得返回的是起点,查询前要下传懒标记,还有就是要把查到的满足条件的区间改为已入住!!!!!

(3)退房:房间状态改为空即可,读题很重要!!!!!!输入的数据是告诉你退房的起点以及区间长度,不管之前是0是1,懒标记全部改0就行了。修改过程中要把父节点的各个长度从左右子树中得来,就像常规线段树更改左右子树结束后父节点权值等于左右子树权值和一样,只不过这道题里要修改以及判断的条件比较多,所以单拎出了一个函数

(4)懒标记下传:下传后清空很重要,有一个点就是区间可能是一个奇数长度,这时候因为查询是靠左优先,而c++里是向下取整,所以有除以二和总长度减除以二的区别

 1 #include<iostream>
 2 using namespace std;
 3 struct shu{
 4     int zq;
 5     int yq;
 6     int tot=0;
 7     int pd=0;
 8 }a[50001*4];
 9 int n,m;
10 void js(int fu,int z,int y)
11 {
12     if(z==y)
13     {
14         a[fu].zq=1;  a[fu].yq=1;
15         a[fu].tot=1;  a[fu].pd=-1;
16         return ;
17     }
18     a[fu].zq=a[fu].yq=a[fu].tot=y-z+1;
19     a[fu].pd=-1;
20     int mid=(z+y)/2;
21     js(fu*2,z,mid);  js(fu*2+1,mid+1,y);
22 }
23 void gx(int fu,int cd)
24 {
25     a[fu].zq=a[fu*2].zq;
26     if(a[fu*2].zq==cd-cd/2)
27         a[fu].zq+=a[fu*2+1].zq;
28     a[fu].yq=a[fu*2+1].yq;
29     if(a[fu*2+1].yq==cd/2)
30         a[fu].yq+=a[fu*2].yq;
31     a[fu].tot=max(max(a[fu*2].tot,a[fu*2+1].tot),a[fu*2].yq+a[fu*2+1].zq);
32 }
33 void down(int fu,int cd)
34 {
35     if(a[fu].pd==-1)  return ;
36     if(a[fu].pd==1)
37     {
38         a[fu*2].zq=a[fu*2].yq=a[fu*2].tot=0;
39         a[fu*2+1].zq=a[fu*2+1].yq=a[fu*2+1].tot=0;
40     }
41     if(a[fu].pd==0)
42     {
43         a[fu*2].zq=a[fu*2].yq=a[fu*2].tot=cd-cd/2;
44         a[fu*2+1].zq=a[fu*2+1].yq=a[fu*2+1].tot=cd/2;
45     }
46     a[fu*2].pd=a[fu*2+1].pd=a[fu].pd;
47     a[fu].pd=-1;
48 }
49 void xg(int fu,int z,int y,int l,int r,int b)
50 {
51     if(l<=z&&r>=y)
52     {
53         a[fu].pd=b;
54         if(b==1)  a[fu].tot=a[fu].zq=a[fu].yq=0;
55         else  a[fu].tot=a[fu].zq=a[fu].yq=y-z+1;
56         return ;
57     }
58     down(fu,y-z+1);
59     int mid=(z+y)/2;
60     if(l<=mid)  xg(fu*2,z,mid,l,r,b);
61     if(r>mid)  xg(fu*2+1,mid+1,y,l,r,b); 
62     gx(fu,y-z+1); 
63 }
64 int cx(int fu,int z,int y,int s)
65 {
66     //if(z==y)  return 1;
67     down(fu,y-z+1);
68     int mid=(z+y)/2;
69     if(a[fu*2].tot>=s)  return cx(fu*2,z,mid,s);
70     if(a[fu*2].yq+a[fu*2+1].zq>=s)  return mid-a[fu*2].yq+1;
71     if(a[fu*2+1].tot>=s)  return cx(fu*2+1,mid+1,y,s); 
72     return 0;
73 }
74 int main()
75 {
76     cin>>n>>m;  js(1,1,n);
77     for(int i=1;i<=m;++i)
78     {
79         int yq;  cin>>yq;
80         if(yq==1)
81         {
82             int cxs;  cin>>cxs;
83             if(a[1].tot<cxs)
84             {
85                 cout<<"0"<<endl;
86                 continue;
87             }
88             int sc=cx(1,1,n,cxs);  cout<<sc<<endl;
89             xg(1,1,n,sc,sc+cxs-1,1);
90         }
91         if(yq==2)
92         {
93             int q,cd;  cin>>q>>cd;
94             xg(1,1,n,q,q+cd-1,0);
95         }
96     }
97     return 0;
98 }
View Code

 

转载于:https://www.cnblogs.com/hzjuruo/p/11296108.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值