roosephu 考題之一: 三維偏序
roosephu的考題,水題倒還是水,難題難的無語。
三維偏序,本來是以前省隊集訓的時候遇到的東西,那時候是徹底被噁心到了,沒寫出來,而這一次仍舊被小小的噁心到了。
原題是給三個1~n的排列列,求三個排列的最長公共子序列。
轉化成三維偏序是比較好想的,而主要問題是這個噁心的三維偏序必須做到nlog^2(n) 的複雜度。
維護偏序一般處理方法是 lzn樹/ 二分歸併/ 樹狀陣列or線段樹,一個東西只能處理一維,所以方法是沒得選的,一維(x)排序,二維(y)歸併,三維(z)樹狀陣列,說的簡單,其實是在不是這麼回事。
排序維護第一維是好理解的。主要是歸併和樹狀陣列如何結合。
排序維護x維之後,遞迴處理:
1.在處理區間[L,R]的時候,先二分割槽間[L, (L+R)/ 2],遞迴求這個左區間(二分的原因是我在維護y維的時候難免破壞x維的性質,但是二分之後我還是可以保證左區間的x全都大於右區間的x)。
2.這個時候左區間y維已經有序,我們只好把右區間[(L+R)/2,R],快排一遍,進行歸併式的dp轉移(左區間一個指標,右區間一個指標,保證左區間指標所掃過的y一定小於右區間指標所掃過的y),然後在用常規的樹狀陣列維護z。
3.當然,最後還應該把右區間[(L+R)/2,R]按x快排回去,並遞迴處理這一段。
4.最後歸併或者快排維護整個區間的y有序。
有點小糾結.............如果寫樹套樹可能比較好理解,但是常數比較大,可以去這裡看看:
程式碼也比較醜,估計沒比樹套樹短多少了:
program lmd; uses math; type arr=array[0..100000]of longint; var f,a,b,c,d,hp :arr; bit,time :array[0..200000]of longint; x,i,n,st,ans,now:longint; procedure inf; begin assign(input,'godfarmer.in'); assign(output,'godfarmer.out'); reset(input); rewrite(output); end; procedure ouf; begin close(input); close(output); end; procedure sort(l,r:longint; var x:arr); var i,j,xy,tmp:longint; begin if l=r then exit; i:=l; j:=r; xy:=d[(l+r) shr 1]; repeat while x[d[i]]<x[xy] do inc(i); while x[d[j]]>x[xy] do dec(j); if i<=j then begin tmp:=d[i]; d[i]:=d[j]; d[j]:=tmp; inc(i); dec(j); end; until i>j; if i<r then sort(i,r,x); if l<j then sort(l,j,x); end; procedure init; begin read(n); for i:=1 to n do begin read(x); a[x]:=i; end; for i:=1 to n do begin read(x); b[x]:=i; end; for i:=1 to n do begin read(x); c[x]:=i; end; for i:=1 to n do d[i]:=i; end; procedure change(x,d:longint); begin while x<=n do begin if time[x]<>now then begin time[x]:=now; bit[x]:=0; end; bit[x]:=max(bit[x],d); x:=x + x and (-x); end; end; function ask(x:longint):longint; begin ask:=0; while x>0 do begin if time[x]=now then ask:=max(ask,bit[x]); x:= x- x and (-x); end; end; procedure make(l,r:longint); var z,i,bi,bj:longint; begin if l=r then begin f[d[l]]:=max(1,f[d[l]]); exit; end; z:=(l+r) shr 1; make(l,z); sort(z+1,r,b); inc(now); bi:=l-1; for bj:=z+1 to r do begin while (b[d[bi+1]]<b[d[bj]]) and (bi<z) do begin inc(bi); change(c[d[bi]],f[d[bi]]); end; f[d[bj]]:=max(f[d[bj]],ask(c[d[bj]])+1); end; sort(z+1,r,a); make(z+1,r); bi:=l-1; hp[0]:=0; for bj:=z+1 to r do begin while (b[d[bi+1]]<b[d[bj]]) and (bi<z) do begin inc(bi); inc(hp[0]); hp[hp[0]]:=d[bi]; end; inc(hp[0]); hp[hp[0]]:=d[bj]; end; while bi<z do begin inc(hp[0]); inc(bi); hp[hp[0]]:=d[bi]; end; for i:=1 to hp[0] do d[i+l-1]:=hp[i]; end; begin inf; init; sort(1,n,a); make(1,n); for i:=1 to n do ans:=max(ans,f[d[i]]); write(ans); ouf; end.