[BZOJ3506]CQOI2014排序机械臂

来源:互联网 发布:编程循环 编辑:程序博客网 时间:2024/05/01 23:28

    挺有意思的。。看到区间翻转好像很容易想到splay,想到之后就没什么难度了。。每个节点维护一个子树最小值,没次删去一个点,该打标记打标记就是。。为了处理同大小的数要以初始序号为第二关键字。。

#include<cstdio>#include<iostream>#define N 100005#define lc c[x][0]#define rc c[x][1]#define inf 2000000005using namespace std;struct Num{int n,xu;}num[N],minn[N];int n,i,nd=0,root=0,rk,t,q[N],c[N][2],size[N],pre[N],rev[N];bool operator==(Num a,Num b){return a.n==b.n&&a.xu==b.xu;}bool operator<(Num a,Num b){if (a.n!=b.n) return a.n<b.n;else return a.xu<b.xu;}void update(int x){size[x]=size[lc]+size[rc]+1;minn[x]=min(min(minn[lc],minn[rc]),num[x]);}void mark(int x){rev[x]^=1;swap(lc,rc);}void down(int x){if (rev[x]) mark(lc),mark(rc),rev[x]=0;}void build(int &x,int l,int r,int fa){if (l>r) return;int mid=(l+r)>>1;x=++nd;num[x].n=q[mid];num[x].xu=mid;pre[x]=fa;build(lc,l,mid-1,x);build(rc,mid+1,r,x);update(x);}void rot(int x,int kind){int y=pre[x],z=pre[y];down(y);pre[c[x][kind]]=y;c[y][!kind]=c[x][kind];pre[y]=x;c[x][kind]=y;pre[x]=z;if (z) c[z][c[z][1]==y]=x;update(y);update(x); }void splay(int x,int goal){int y,z,kind;while (pre[x]!=goal)if (pre[y=pre[x]]==goal) rot(x,c[y][0]==x);else{int z=pre[y],kind=(c[z][0]==y);down(z);if (c[y][kind]==x) rot(x,!kind);else rot(y,kind);rot(x,kind);}if (goal==0) root=x;}int merge(int s1,int s2){int x=s1;down(x);while (c[x][1]) x=c[x][1],down(x);splay(x,pre[s1]);c[x][1]=s2;pre[s2]=x;update(x);return x;}void del(int x){splay(x,0);down(x);if (lc*rc==0) root=lc+rc;else root=merge(lc,rc);pre[root]=0;}int get(int x){down(x);if (minn[x]==num[x]){rk+=size[lc];return x;}if (minn[lc]<minn[rc]) return get(lc);else{rk+=size[lc]+1;return get(rc);}}int main(){scanf("%d",&n);for (i=1;i<=n;i++) scanf("%d",&q[i]),rev[i]=0;size[0]=0;num[0].n=minn[0].n=inf;build(root,1,n,0);for (i=1;i<=n;i++){rk=0;t=get(root);splay(t,0);mark(c[t][0]);del(t);printf("%d ",rk+i);}}


0 0
原创粉丝点击