这题的建模有点不太一样,是按结点横坐标赋予键值的
同时每次rotate和splay时都要注意下往上往下更新
/* 先建立好splay tree,将结点按num/输入顺序排序,遍历时每次将当前结点提到根节点,输出其在splay树中排第几个 然后rev左子树,最后remove */ #include<iostream> #include<cstring> #include<cstdio> using namespace std; #include<algorithm> #define maxn 100005 struct A{ int num,id; bool operator < (const A &a) const { if(num==a.num) return id<a.id; return num<a.num; } }a[maxn]; int pre[maxn],ch[maxn][2],size[maxn],keys[maxn],tot,root,n; int rev[maxn]; inline void pushup(int r){ size[r]=size[ch[r][0]]+size[ch[r][1]]+1; } void update(int r){//就是交换r的两个子区间 if(!r) return; else { swap(ch[r][0],ch[r][1]); rev[r]^=1; } } inline void pushdown(int r){ if(rev[r]){//把左右子树rev update(ch[r][0]); update(ch[r][1]); rev[r]=0; } } inline void newnode(int &r,int fa,int key){ r=key; pre[r]=fa; ch[r][0]=ch[r][1]=0; size[r]=0; keys[r]=key; rev[r]=0; } void build(int &r,int L,int R,int fa){ if(L>R) return; int m=L+R>>1; newnode(r,fa,m); build(ch[r][0],L,m-1,r); build(ch[r][1],m+1,R,r); pushup(r); } void init(){ root=tot=0; ch[root][0]=ch[root][1]=0; size[root]=0; rev[root]=0; build(root,1,n,0); } //rotate操作只会改变r,fa,ch[r][kind]三个结点 void rotate(int x,int kind){ int fa=pre[x]; pushdown(fa); pushdown(x); ch[fa][!kind]=ch[x][kind]; pre[ch[x][kind]]=fa; if(pre[fa]) ch[pre[fa]][ch[pre[fa]][1]==fa]=x; pre[x]=pre[fa]; pre[fa]=x; ch[x][kind]=fa; pushup(fa); pushup(x); } void splay(int r,int goal){ pushdown(r); while(pre[r]!=goal){ if(pre[pre[r]]==goal){ pushdown(pre[r]); pushdown(r); rotate(r,ch[pre[r]][0]==r); } else { pushdown(pre[pre[r]]); pushdown(pre[r]); pushdown(r); int fa=pre[r]; int kind=(ch[pre[fa]][0]==fa); if(ch[fa][kind]==r){//方向相反 rotate(r,!kind); rotate(r,kind); } else { rotate(fa,kind); rotate(r,kind); } } } if(goal==0) root=r; pushup(r); } void remove(){//删掉根节点 if(ch[root][0]==0){ root=ch[root][1]; pre[root]=0; } else { pushdown(root); int tmp=ch[root][0]; while(ch[tmp][1]) pushdown(tmp),tmp=ch[tmp][1]; splay(tmp,root); ch[tmp][1]=ch[root][1]; pre[ch[root][1]]=tmp; root=tmp; pre[root]=0; pushup(root); } } int main(){ while(scanf("%d",&n) && n){ init(); for(int i=1;i<=n;i++) scanf("%d",&a[i].num),a[i].id=i; sort(a+1,a+1+n); for(int i=1;i<n;i++){ splay(a[i].id,0);//按权值大小遍历点 update(ch[root][0]);//逆转区间 printf("%d ",i+size[ch[root][0]]);//输出结点在当前伸展树中排的序号 remove(); } printf("%d\n",n); } return 0; }