一向對資料結構不感冒,這次有所改觀
盾哥對SPLAY 的崇拜使我也開始對這種感覺還比較好用的資料結構產生了興趣
先分析下SPLAY的特點:
1.它能維護一個序列,動態地支援一些操作(主要是區間型操作),任意時刻它的中序遍曆都是當前序列,這棵樹其實是以位置為“序”的
2.它可以通過提根操作完成區間型操作,這裡要用到類似與線段樹的LAZY標記,更基本的操作就是旋轉
3.可擴充性非常好,支援非常多的操作,感覺上線段樹能搞定的,splay基本上都沒什麼問題
4.它的常數因子非常大,O(logN)真的只是“理論”複雜度
5.標準的splay有一大堆旋轉和一大堆特判,編程複雜度奇高無比,其實不實用。個人感覺裸提根(就是只用樸素的左旋右旋)也還不錯,對於編程速度要求很高的各大oi比賽中,較低的編程複雜度可能會更合適
6.初始的建樹如果想偷懶就直接建成一條鏈,然後一頓亂旋幾下,而要求高點可能就要建成一棵完全二叉樹了
7.由於每個點攜帶的資訊不多,空間上比線段樹什麼的稍微好點
大概就這樣吧,可以看到,splay還是相當不錯的,下面接著看這道題
題目大意:
維護一個序列,支援下列操作:
1.插入刪除;
2.翻轉一段選定的序列;
3.交換兩段相鄰的序列;
4.一段全部增加k;
5.詢問一段的最小值。
分析:
看到一大堆的操作就應該想到是到資料結構題,由於要完成區間型操作,可以會先想到線段樹,但動態插入和刪除貌似用線段樹不好搞定,怎麼辦?splay這種強大的資料結構便能讓我們脫離苦海,駛向ac的彼岸
演算法:
用splay維護這個序列(先搞個極小極大點),對於每個操作:
1.插入 j 到 i 後面:
首先把i提根,在建立節點 j,使得r[j]=r[i];r[i]=j; 再維護j,i的資訊即可;
2.刪除i:
首先把i提根,再把 i+1提根,接著把 l[i+1]=l[i],維護i+1,這樣 i 就被刪除了;
3.翻轉(增加)區間[a,b]:
先把a-1提根,再把b+1提根,這時候,以r[l[root]]就是我們要的區間,再用線段樹的lazy思想,把標記放上去並維護就可以了;
4.交換相鄰兩段序列[a,b],[b+1,c](所謂的revolve其實就是這個,自己想一想):
這個操作稍微麻煩一點,先把b提根,再把a-1提為b的左兒子,接著把c+1提為b的右兒子,這時把l[r[root]](即區間[b+1,c])作為l[root]的右兒子,而原來的右兒子作為root的左兒子。此時發現root和原來的l[root]這顆子樹中斷連線了,我們需要把此時以root為根的樹的最小的點提出來作為根,再把原來的l[root]置為 root‘ 的左兒子,操作完成。
編寫的時候還是出現了一些問題的,要不會像盾哥一樣調到晚上一點多(結果第二天遲到了),如:
1.min數組在標記下放的是後可以同加同減,不用再從下面更新了,更新也是錯的。
2.標記下方完後清空。
3.因為一開始就建立了n+2個點,所以記總點數一開始即為n+2
好了,只用了145行就搞定,而且交這道題時是1遍ac,小小的爽了一把。
代碼:
program syj_splay;<br />const<br /> maxn=100000+5;<br /> oo=maxlongint shr 1;<br />var n,root,task:longint;<br /> a,son,l,r,b1,b2,mi:array[0..maxn+maxn]of longint;<br />function min(x,y:longint):longint;<br />begin<br /> if x<y then min:=x<br /> else min:=y;<br />end;<br />procedure init;<br />var i:longint;<br />begin<br /> readln(n);<br /> root:=n+2;<br /> for i:=2 to n+1 do begin<br /> readln(a[i]);l[i]:=i-1;son[i]:=i;mi[i]:=a[i];<br /> end;<br /> l[n+2]:=n+1;son[1]:=1;son[n+2]:=n+2;mi[0]:=oo;mi[1]:=oo;mi[n+2]:=oo;a[1]:=oo;a[n+2]:=oo;<br /> n:=n+2;<br />end;<br />procedure update(i:longint);<br />begin<br /> son[i]:=son[l[i]]+son[r[i]]+1;<br /> mi[i]:=min(min(mi[l[i]],mi[r[i]]),a[i]);<br />end;<br />procedure left(var i:longint);<br />var j:longint;<br />begin<br /> j:=r[i];r[i]:=l[j];l[j]:=i;<br /> update(i);update(j);<br /> i:=j;<br />end;<br />procedure right(var i:longint);<br />var j:longint;<br />begin<br /> j:=l[i];l[i]:=r[j];r[j]:=i;<br /> update(i);update(j);<br /> i:=j;<br />end;<br />procedure put1(i,j:longint);<br />begin<br /> if i=0 then exit;<br /> a[i]:=a[i]+j;mi[i]:=mi[i]+j;<br /> b1[i]:=b1[i]+j;<br />end;<br />procedure put2(i:longint);<br />var z:longint;<br />begin<br /> if i=0 then exit;<br /> z:=l[i];l[i]:=r[i];r[i]:=z;<br /> b2[i]:=1-b2[i];<br />end;<br />procedure up(var i:longint;k:longint);<br />begin<br /> if i=0 then exit;<br /> if b1[i]>0 then begin<br /> put1(l[i],b1[i]);put1(r[i],b1[i]);<br /> b1[i]:=0;<br /> end;<br /> if b2[i]>0 then begin<br /> put2(l[i]);put2(r[i]);<br /> b2[i]:=0;<br /> end;<br /> if k<=son[l[i]] then begin<br /> up(l[i],k);right(i);<br /> end<br /> else<br /> if k>son[l[i]]+1 then begin<br /> up(r[i],k-son[l[i]]-1);left(i);<br /> end;<br />end;<br />procedure work;<br />var i,j,k,kk,c,z:longint;<br /> st:string;<br />begin<br /> readln(task);<br /> for task:=1 to task do begin<br /> readln(st);<br /> while st[length(st)]=' ' do delete(st,length(st),1);st:=st+' ';<br /> if (st[1]='A') then c:=1 else<br /> if (st[1]='R')and(st[4]='E') then c:=2 else<br /> if (st[1]='R')and(st[4]='O') then c:=3 else<br /> if (st[1]='I') then c:=4 else<br /> if (st[1]='D') then c:=5 else c:=6;<br /> delete(st,1,pos(' ',st));<br /> val(copy(st,1,pos(' ',st)-1),i,z);<br /> delete(st,1,pos(' ',st));<br /> if length(st)>1 then begin<br /> val(copy(st,1,pos(' ',st)-1),j,z);<br /> delete(st,1,pos(' ',st));<br /> if length(st)>1 then val(copy(st,1,length(st)-1),k,z);<br /> end;<br /> case c of<br /> 1:begin<br /> inc(i);inc(j);<br /> up(root,i-1);up(root,j+1);<br /> put1(r[l[root]],k);<br /> end;<br /> 2:begin<br /> inc(i);inc(j);<br /> up(root,i-1);up(root,j+1);<br /> put2(r[l[root]]);<br /> end;<br /> 3:begin<br /> inc(i);inc(j);<br /> up(root,i-1);up(root,j+1);k:=k mod (j-i+1);<br /> if k>0 then begin<br /> kk:=r[l[root]];<br /> up(kk,j-k-i+1);<br /> up(r[kk],k);<br /> z:=r[kk];r[z]:=kk;r[l[root]]:=z;r[kk]:=0;<br /> update(r[z]);update(z);<br /> end;<br /> end;<br /> 4:begin<br /> inc(i);<br /> inc(n);a[n]:=j;mi[n]:=j;j:=n;<br /> up(root,i);r[j]:=r[root];r[root]:=j;<br /> update(j);update(root);<br /> end;<br /> 5:begin<br /> inc(i);<br /> up(root,i);<br /> up(r[root],1);<br /> l[r[root]]:=l[root];root:=r[root];<br /> update(root);<br /> end;<br /> 6:begin<br /> inc(i);inc(j);<br /> up(root,i-1);up(root,j+1);<br /> writeln(mi[r[l[root]]]);<br /> end;<br /> end;<br /> end;<br />end;<br />begin<br /> assign(input,'pku3580.in');reset(input);<br /> assign(output,'pku3580.out');rewrite(output);<br /> init;<br /> work;<br /> close(input);<br /> close(output);<br />end.<br />
一題一結構,無題不演算法