bzoj 1251: 序列终结者 2011-12-20
1251: 序列终结者Time Limit: 20 Sec Memory Limit: 162 MB
Submit: 650 Solved: 277
[Submit][Status][Discuss]Description
网上有许多题,就是给定一个序列,要你支持几种操作:A、B、C、D。一看另一道题,又是一个序列
要支持几种操作:D、C、B、A。尤其是我们这里的某人,出模拟试题,居然还出了一道这样的,真是没技术含量……这样
我也出一道题,我出这一道的目的是为了让大家以后做这种题目有一个“库”可以依靠,没有什么其他的意思。这道题目 就叫序列终结者吧。 【问题描述】
给定一个长度为N的序列,每个序列的元素是一个整数(废话)。要支持以下三种操作: 1. 将[L,R]这个区间内的所有数加上V。 2.
将[L,R]这个区间翻转,比如1 2 3 4变成4 3 2 1。 3. 求[L,R]这个区间中的最大值。
最开始所有元素都是0。Input第一行两个整数N,M。M为操作个数。
以下M行,每行最多四个整数,依次为K,L,R,V。K表示是第几种操作,如果不是第1种操作则K后面只有两个数。Output对于每个第3种操作,给出
正确的回答。Sample Input4 4
1 1 3 2
1 2 4 -1
2 1 3
3 2 4
Sample Output2
【数据范围】
N<=50000,M<=100000。
___________________________________________
那个,八中,有点坑,程序也有点坑,所以只好把外挂都开启了。
___________________________________________
1 Program Stone; 2 3 {$inline on} 4 5 {$A+,B-,D-,E-,F-,G+,I-,L-,N+,O-,P+,Q-,R-,S-,T-,V-,X+,Y-} 6 7 {$M 65520,0,655360} 8 9 var i,j,k,n,m,root,lx,rx,v,qu:longint; 10 11 a,lc,rc,f,o,bi,q:array[0..100000]of longint; 12 13 c:array[0..100000]of boolean; //是否翻转,即是否交换左右孩子 14 15 16 17 Procedure built(x,y:longint);inline;//先建树,一棵比较平衡的树! 18 19 var i,k:longint; 20 21 begin 22 23 k:=(x+y)div 2; //k为根节点,小于k的为左子树,大于k的为右子树。 24 25 q[k]:=y-x+1; 26 27 if y=x then exit; 28 29 if x<=k-1 then begin 30 31 built(x,k-1); 32 33 i:=(x+k-1)div 2; 34 35 f[i]:=k;lc[k]:=i; 36 37 end; 38 39 if y>=k+1 then begin 40 41 built(k+1,y); 42 43 i:=(y+k+1)div 2; 44 45 f[i]:=k;rc[k]:=i; 46 47 end; 48 49 end; 50 51 procedure Tonext(x:longint);inline; //将节点的状态传递给子节点 52 53 var i,j:longint; 54 55 begin 56 57 inc(a[x],o[x]); 58 59 if (lc[x]>1)and(lc[x]<n+2) then begin //判断孩子节点是否在整段序列中 60 61 inc(o[lc[x]],o[x]); 62 63 inc(bi[lc[x]],o[x]); 64 65 c[lc[x]]:=c[lc[x]]xor c[x]; 66 67 end; 68 69 if (rc[x]>1)and(rc[x]<n+2) then begin 70 71 inc(o[rc[x]],o[x]); 72 73 inc(bi[rc[x]],o[x]); 74 75 c[rc[x]]:=c[rc[x]]xor c[x]; 76 77 end; 78 79 if c[x] then begin //如果需要翻转,就交换左右孩子。 80 81 i:=lc[x];lc[x]:=rc[x];rc[x]:=i; 82 83 end; 84 85 o[x]:=0; //修改状态 86 87 c[x]:=false; 88 89 end; 90 91 92 93 function max(a,b,c:longint):longint;inline; 94 95 begin 96 97 if a>b then max:=a else max:=b; 98 99 if c>max then max:=c; 100 101 end; 102 103 104 105 procedure change(x:longint);inline; //旋转时改变记录,q为以该节点为根的树有多少个节点。bi为这棵树中的最大值。 106 107 begin 108 109 q[x]:=q[lc[x]]+q[rc[x]]+1; 110 111 bi[x]:=max(bi[lc[x]],bi[rc[x]],a[x])+o[x]; 112 113 end; 114 115 116 117 procedure rightturn(x:longint);inline; //右旋 118 119 var i,j,k:longint; 120 121 begin 122 123 k:=f[x]; 124 125 if k=lc[f[k]] then lc[f[k]]:=x else rc[f[k]]:=x; 126 127 f[x]:=f[k]; 128 129 lc[k]:=rc[x];f[lc[k]]:=k; 130 131 rc[x]:=k;f[k]:=x; 132 133 change(k); 134 135 end; 136 137 138 139 procedure leftturn(x:longint); inline; //左旋 140 141 var i,j,k:longint; 142 143 begin 144 145 k:=f[x]; 146 147 if k=lc[f[k]] then lc[f[k]]:=x else rc[f[k]]:=x; 148 149 f[x]:=f[k]; 150 151 rc[k]:=lc[x];f[rc[k]]:=k; 152 153 lc[x]:=k;f[k]:=x; 154 155 change(k); 156 157 end; 158 159 160 161 Procedure splay(x,root:longint);inline; //splay 162 163 var i,j,k:longint; 164 165 begin 166 167 if x=root then exit; 168 169 while f[x]<>root do 170 171 begin 172 173 k:=f[x]; 174 175 if x=lc[k] then begin 176 177 if f[k]=root then rightturn(x) 178 179 else if k=lc[f[k]] then begin 180 181 rightturn(k); 182 183 rightturn(x); 184 185 end 186 187 else begin 188 189 rightturn(x); 190 191 leftturn(x); 192 193 end; 194 195 end 196 197 else begin 198 199 if f[k]=root then leftturn(x) 200 201 else if k=rc[f[k]] then begin 202 203 leftturn(k); 204 205 leftturn(x); 206 207 end 208 209 else begin 210 211 leftturn(x); 212 213 rightturn(x); 214 215 end; 216 217 end; 218 219 end; 220 221 change(x); 222 223 end; 224 225 226 227 procedure toroot(x:longint);inline; //更新父亲节点,直到根为止 228 229 begin 230 231 if x=0 then exit; 232 233 bi[x]:=max(bi[lc[x]],bi[rc[x]],a[x])+o[x]; 234 235 toroot(f[x]); 236 237 end; 238 239 240 241 procedure findk(s,x:longint);inline; //寻找 242 243 begin 244 245 tonext(x); 246 247 if q[lc[x]]+1=s then qu:=x; 248 249 if q[lc[x]]+1<s then findk(s-q[lc[x]]-1,rc[x]); 250 251 if q[lc[x]]+1>s then findk(s,lc[x]); 252 253 end; 254 255 256 257 procedure init; inline; 258 259 var i,j,k:longint; 260 261 begin 262 263 readln(n,m); 264 265 a[1]:=-maxlongint;a[n+2]:=-maxlongint;a[0]:=-maxlongint;bi[0]:=-maxlongint; 266 267 //在序列左边插入一个节点,右边也插入一个节点,作为边界。注意0节点的初始化。 268 269 built(1,n+2);root:=(1+n+2)div 2; 270 271 fillchar(c,sizeof(c),false); 272 273 for i:=1 to m do 274 275 begin 276 277 read(k,lx,rx); 278 279 inc(lx);inc(rx); 280 281 findk(lx-1,root);lx:=qu; //寻找询问区间左边界,边界即为询问区间最左边的节点-1 282 283 findk(rx+1,root);rx:=qu;//寻找询问区间右边界,..........最右边的节点+1 284 285 splay(lx,0);root:=lx; //将lx旋转到根节点,rx旋转到根节点的右孩子节点,这样rx的左孩子即为询问区间。 286 287 splay(rx,root); 288 289 case k of //3种操作 290 291 1:begin 292 293 read(v); 294 295 inc(o[lc[rx]],v); //修改状态 296 297 inc(bi[lc[rx]],v); 298 299 toroot(rx); //更新父亲节点的最大值记录 300 301 end; 302 303 2:begin 304 305 c[lc[rx]]:=not(c[lc[rx]]); //翻转,改变翻转记录 306 307 end; 308 309 3:begin 310 311 writeln(bi[lc[rx]]); 312 313 end; 314 315 end; 316 317 end; 318 319 end; 320 321 Begin 322 323 assign(input,'input.in');reset(input); 324 325 assign(output,'output1.out');rewrite(Output); 326 327 init; 328 329 close(output); 330 331 end.
_____MildTheorem