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.