POJ3667 Hotel

题目大意:

  有一段长为n的线段,在这条线段上进行操作:

  1.找出最靠前的长度为l的空线段,并把一个长为l的线段插入在这个地方.

  2.删除从某点开始长为l的一段线段(有可能并不存在,总之就是把这个区间清空).

  输出每次插入操作的位置.

题目分析

  线段树的经典题,练习块状链表写的好长啊,伤心ing

  用块状链表的话,对于每一个块需要维护以下信息,包含左端点的最长空白,包含右端点的最长空白,这一块内的最长空白及其开始位置,最后是该块是否被完全赋值的标记。

  对于查找操作,我们从头向后查找,维护包含当前块的最长空白长度,注意处理答案存在于块的头部的信息,而且当一个块内有答案时,他不一定是最长空白,需要扫描一遍当前块,从而找到满足条件的最靠前的位置。之后将答案占用的那一段赋成不可用。

  对于整段赋值的操作,头尾两端暴力修改,中间段直接维护标记,之前有标记的要预先下放标记。

  最重要的是当一个块被修改后在sqrt(n)时间内更新信息,左右最大空白段很好维护,对于块内最长空白段,可以用一遍扫描来得到,具体实现只需要维护一个变量表示向前最远的连续空白位置。

  代码比较长,但是很清晰。update是更新块信息,use将一段赋值不可用,blank将一段清空,find查找答案。下标统一从0开始。

View Code
  1 program hotel(input,output);
  2 var
  3     head,tail:array[0..5000] of longint;
  4     limit,size,n,m:longint;
  5     can:array[0..61000] of boolean;
  6     bj,maxl,maxr,maxp,maxb:array[0..5000] of longint;
  7 procedure build();
  8 var
  9     i:longint;
 10 begin
 11     limit:=trunc(sqrt(n+1));
 12     size:=(n+1) div limit;
 13     if ((n+1) mod limit=0) then
 14         dec(size);
 15     for i:=0 to size do
 16     begin
 17         head[i]:=i*limit;
 18         tail[i]:=(i+1)*limit-1;
 19     end;
 20     tail[size]:=n;
 21     for i:=0 to size do
 22     begin
 23         maxl[i]:=tail[i]-head[i]+1;
 24         maxr[i]:=tail[i]-head[i]+1;
 25         maxp[i]:=tail[i]-head[i]+1;
 26         maxb[i]:=head[i];
 27         bj[i]:=0;
 28     end;
 29 end;{ build }
 30 procedure init;
 31 begin
 32     readln(n,m);
 33     dec(n);
 34     fillchar(can,sizeof(can),true);
 35     build();
 36 end;{ init }
 37 procedure update(now:longint);
 38 var
 39     i,last:longint;
 40 begin
 41     if bj[now]=1 then
 42     begin
 43         maxl[now]:=tail[now]-head[now]+1;
 44         maxr[now]:=tail[now]-head[now]+1;
 45         maxp[now]:=tail[now]-head[now]+1;
 46         maxb[now]:=head[now];
 47         exit;
 48     end;
 49     if bj[now]=-1 then
 50     begin
 51         maxl[now]:=0;
 52         maxr[now]:=0;
 53         maxp[now]:=0;
 54         maxb[now]:=head[now];
 55         exit;
 56     end;
 57     maxl[now]:=tail[now]-head[now]+1;
 58     for i:=head[now] to tail[now] do
 59         if not can[i] then
 60         begin
 61             maxl[now]:=i-head[now];
 62             break;
 63         end;
 64     maxr[now]:=tail[now]-head[now]+1;
 65     for i:=tail[now] downto head[now] do
 66         if (not can[i]) then
 67         begin
 68             maxr[now]:=tail[now]-i;
 69             break;
 70         end;
 71     last:=head[now];
 72     maxp[now]:=0;
 73     maxb[now]:=head[now];
 74     for i:=head[now] to tail[now] do
 75         if not can[i] then
 76         begin
 77             if i-last>maxp[now] then
 78             begin
 79                 maxp[now]:=i-last;
 80                 maxb[now]:=last;
 81             end;
 82             last:=i+1;
 83         end;
 84     if not can[last] then
 85         inc(last);
 86     if tail[now]+1-last>maxp[now] then
 87     begin
 88         maxp[now]:=tail[now]+1-last;
 89         maxb[now]:=last;
 90     end;
 91 end;{ update }
 92 procedure blank(l,r:longint);
 93 var
 94     ll,rr,i:longint;
 95 begin
 96     ll:=l div limit;
 97     rr:=r div limit;
 98     if bj[ll]<>0 then
 99     begin
100         if bj[ll]=1 then
101             for i:=head[ll] to tail[ll] do
102                 can[i]:=true
103         else
104             for i:=head[ll] to tail[ll] do
105                 can[i]:=false;
106         bj[ll]:=0;
107     end;
108     if bj[rr]<>0 then
109     begin
110         if bj[rr]=1 then
111             for i:=head[rr] to tail[rr] do
112                 can[i]:=true
113         else
114             for i:=head[rr] to tail[rr] do
115                 can[i]:=false;
116         bj[rr]:=0;
117     end;    
118     if ll=rr then
119     begin
120         for i:=l to r do
121             can[i]:=true;
122         update(ll);
123         exit;
124     end;
125     for i:=l to tail[ll] do
126         can[i]:=true;
127     update(ll);
128     for i:=head[rr] to r do
129         can[i]:=true;
130     update(rr);
131     for i:=ll+1 to rr-1 do
132     begin
133         bj[i]:=1;
134         update(i);
135     end;
136 end;{ blank }
137 procedure use(l,r:longint);
138 var
139     ll,rr,i:longint;
140 begin
141     ll:=l div limit;
142     rr:=r div limit;
143     if bj[ll]<>0 then
144     begin
145         if bj[ll]=1 then
146             for i:=head[ll] to tail[ll] do
147                 can[i]:=true
148         else
149             for i:=head[ll] to tail[ll] do
150                 can[i]:=false;
151         bj[ll]:=0;
152     end;
153     if bj[rr]<>0 then
154     begin
155         if bj[rr]=1 then
156             for i:=head[rr] to tail[rr] do
157                 can[i]:=true
158         else
159             for i:=head[rr] to tail[rr] do
160                 can[i]:=false;
161         bj[rr]:=0;
162     end;    
163     if ll=rr then
164     begin
165         for i:=l to r do
166             can[i]:=false;
167         update(ll);
168         exit;
169     end;
170     for i:=l to tail[ll] do
171         can[i]:=false;
172     update(ll);
173     for i:=head[rr] to r do
174         can[i]:=false;
175     update(rr);
176     for i:=ll+1 to rr-1 do
177     begin
178         bj[i]:=-1;
179         update(i);
180     end;
181 end;{ use }
182 function find(l:longint):longint;
183 var
184     i,sum,pp,now,ss:longint;
185 begin
186     if maxp[0]>=l then
187     begin
188         find:=maxb[0];
189         now:=head[0];
190         while now<=tail[0] do
191         begin
192             ss:=0;
193             while (can[now])and(now<=tail[0]) do
194             begin
195                 inc(ss);
196                 inc(now);
197             end;
198             if ss>=l then
199             begin
200                 find:=now-ss;
201                 break;
202             end;
203             inc(now);
204         end;
205         use(find,find+l-1);
206         exit;
207     end;
208     sum:=maxr[0];
209     pp:=tail[0]-maxr[0]+1;
210     for i:=1 to size do
211     begin
212         if sum+maxl[i]>=l then
213         begin
214             find:=pp;
215             use(pp,pp+l-1);
216             exit;
217         end
218         else
219         begin
220             if maxp[i]>=l then
221             begin
222                 find:=maxb[i];
223                 now:=head[i];
224                 while now<=tail[i] do
225                 begin
226                     ss:=0;
227                     while (can[now])and(now<=tail[i]) do
228                     begin
229                         inc(ss);
230                         inc(now);
231                     end;
232                     if ss>=l then
233                     begin
234                         find:=now-ss;
235                         break;
236                     end;
237                     inc(now);
238                 end;
239                 use(find,find+l-1);
240                 exit;
241             end;
242             if maxl[i]=tail[i]-head[i]+1 then
243                 sum:=sum+maxl[i]
244             else
245             begin
246                 pp:=tail[i]-maxr[i]+1;
247                 sum:=maxr[i];
248             end;
249         end;
250     end;
251     exit(-1);
252 end;{ find }
253 procedure main;
254 var
255     i,xx,yy,ww:longint;
256 begin
257     for i:=1 to m do
258     begin
259         read(xx);
260         if xx=1 then
261         begin
262             readln(yy);
263             writeln(find(yy)+1);
264         end
265         else
266         begin
267             readln(yy,ww);
268             blank(yy-1,yy+ww-2);
269         end;
270     end;
271 end;{ main }
272 begin
273     init;
274     main;
275 end.
原文地址:https://www.cnblogs.com/neverforget/p/2748093.html