Luogu P3165 [CQOI2014]排序機械臂
阿新 • • 發佈:2019-01-14
先講一下和這題一起四倍經驗的題:
這題作為一道十分經典的平衡樹維護序列的問題,自然是值得一做的了。
寫完翻了下題解發現都是寫Splay的dalao,少有的暴力FHQ_Treap黨還是用指標實現的。
所以這裡略微講解下陣列實現的FHQ_Treap好了,感覺寫起來比Splay舒服些。
首先我們要抽象化一下題意:給你\(n\)個數,第\(i\)次操作在\([i,n]\)中找到最小值的位置\(p_i\),並翻轉
然後我們考慮轉化問題(因為貌似FHQ_Treap不能同時支援基於權值的split
和基於排名的分裂)。
所以離散化是必須的,尤其注意這裡不能直接對陣列排序(因為會有權值相等的點)。
然後我們記一下每個值原來的位置,再考慮對一個基本序列(即初始時為\(1,2,3,\dots,n\))進行翻轉。
手動推導一下我們發現其實就是先找出每次操作位置的排名,然後再基本序列上不停翻轉區間即可。
由於FHQ_Treap樹高期望\(\log\)的特性,所以我們查詢排名的時候可以直接暴力從一個點跳到根然後反著算回來。
最後提一下那種以權值為保證堆性質的值的做法是錯誤
CODE
#include<cstdio> #include<cctype> #include<algorithm> #define RI register int #define CI const int& #define Tp template <typename T> using namespace std; const int N=100005; struct data { int val,id; inline friend bool operator <(const data& A,const data& B) { return A.val<B.val||(A.val==B.val&&A.id<B.id); } }a[N]; int n,rk; class FileInputOutput { private: static const int S=1<<21; #define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++) #define pc(ch) (Ftop<S?Fout[Ftop++]=ch:(fwrite(Fout,1,S,stdout),Fout[(Ftop=0)++]=ch)) char Fin[S],Fout[S],*A,*B; int Ftop,pt[15]; public: Tp inline void read(T& x) { x=0; char ch; while (!isdigit(ch=tc())); while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc())); } Tp inline void write(T x) { if (!x) return (void)(pc('0'),pc(' ')); RI ptop=0; while (x) pt[++ptop]=x%10,x/=10; while (ptop) pc(pt[ptop--]+48); pc(' '); } inline void Fend(void) { fwrite(Fout,1,Ftop,stdout); } #undef tc #undef pc }F; class FHQ_Treap { private: struct treap { int ch[2],size,dat,fa; bool rev; inline treap(CI Dat=0,CI Size=0) { ch[0]=ch[1]=rev=fa=0; dat=Dat; size=Size; } }node[N]; int tot,rt,seed,stack[N],top; #define lc(x) node[x].ch[0] #define rc(x) node[x].ch[1] #define fa(x) node[x].fa inline int rand(void) { return seed=(int)seed*482711LL%2147483647; } inline void swap(int& x,int& y) { int t=x; x=y; y=t; } inline void rever(CI x) { swap(lc(x),rc(x)); node[x].rev^=1; } inline void pushup(CI x) { node[x].size=node[lc(x)].size+node[rc(x)].size+1; fa(lc(x))=fa(rc(x))=x; } inline void pushdown(CI x) { if (node[x].rev) rever(lc(x)),rever(rc(x)),node[x].rev=0; } inline void merge(int& now,int x,int y) { if (!x||!y) return (void)(now=x|y); if (node[x].dat>node[y].dat) pushdown(x),now=x,merge(rc(now),rc(x),y),pushup(x); else pushdown(y),now=y,merge(lc(now),x,lc(y)),pushup(y); } inline void split(int now,int& x,int& y,int rk) { if (!now) return (void)(x=y=0); pushdown(now); if (node[lc(now)].size<rk) x=now,split(rc(now),rc(x),y,rk-node[lc(now)].size-1); else y=now,split(lc(now),x,lc(y),rk); pushup(now); } public: FHQ_Treap() { seed=233; } inline void insert(CI val) { node[++tot]=treap(rand(),1); merge(rt,rt,tot); } inline void reverse(RI l,RI r) { int x,y,z; split(rt,x,y,l-1); split(y,y,z,r-l+1); rever(y); merge(y,y,z); merge(rt,x,y); } inline int get_rk(int now) { stack[top=1]=now; for (int t=now;fa(t);t=fa(t)) stack[++top]=fa(t); while (top) pushdown(stack[top--]); int ret=node[lc(now)].size; for (;now;now=fa(now)) if (now==rc(fa(now))) ret+=node[lc(fa(now))].size+1; return ret+1; } #undef lc #undef rc }T; int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); RI i; for (F.read(n),i=1;i<=n;++i) F.read(a[i].val),a[i].id=i; for (sort(a+1,a+n+1),i=1;i<=n;++i) T.insert(i); for (i=1;i<=n;++i) rk=T.get_rk(a[i].id),F.write(rk),T.reverse(i,rk); return F.Fend(),0; }