题解 P3165 【[CQOI2014]排序机械臂】

wuzhoupei

2018-01-25 20:55:36

Solution

![Peipei](http://img.blog.csdn.net/20180120093509502?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcHJldGVuZF9mYWw=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) 还是我的Logo >\_< 看别的题解好长好难理解 那我们写个短的 首先 这是一个平衡树 这个题要求是 查询第 k 小并反转某个区间 所以呢 # **fhq Treap** 啊 我们权值为输入的下标, 建一个fhq Treap 然后以该点的权值作为优先级,使之成为小根堆 这样当前 Treap 的堆顶就是当前最小值 于是我们就直接取堆顶, 然后删除 至于旋转, 我们在删除之前 在堆顶的左子树中打上 lazy 标记就好了 然后删掉堆顶 因为我们是按照位置为权值,那么左子树的所有点都在当序列中前节点的左侧 即需要翻转的地方 所以我们就写一个甚至只需要 merge 的 fhq Treap 就好了 棒棒哒 ```cpp #include <bits/stdc++.h> #define II long long #define IL inline #define R register #define I 123456 #define PI 100000 using namespace std; IL void of(R II &a) { R char c=getchar(); R II w=1, p=0; while (c<'0' || c>'9') { if(c=='-') w=-1; c=getchar(); } while (c>='0' && c<='9') { p=p*10+c-'0'; c=getchar(); } a=w*p; } /* -------------------- Peipei -------------------- */ II n,root; struct owo { II l,r,w,ra,siz,lazy; } Tr[I]; IL void up(R II o) { Tr[o].siz=Tr[Tr[o].l].siz+Tr[Tr[o].r].siz+1; } IL void updata(R II o) { if(Tr[o].lazy) { R II l=Tr[o].l, r=Tr[o].r; swap(Tr[o].l,Tr[o].r); if(l) Tr[l].lazy^=1; if(r) Tr[r].lazy^=1; Tr[o].lazy=0; } } IL II merge(R II l,R II r) { if(l*r==0) return l+r; if(Tr[l].ra<Tr[r].ra) { updata(l); Tr[l].r=merge(Tr[l].r,r); up(l); return l; } else { updata(r); Tr[r].l=merge(l,Tr[r].l); up(r); return r; } } int main() { // freopen("1.in","r",stdin); of(n); for(R II i=1,x;i<=n;i++) { of(x); x=x*PI+i; Tr[i]=(owo) {0,0,i,x,1,0}; root=merge(root,i); } for(R II i=1,l,r;i<=n;i++) { updata(root); printf("%lld ",Tr[Tr[root].l].siz+i); l=Tr[root].l; r=Tr[root].r; Tr[root].l=Tr[root].r=0; Tr[l].lazy^=1; root=merge(l,r); } exit(0); } ``` 是不是特别短??! 【滑稽】