CQOI2014 排序机械臂

Description

  为了把工厂中 高低不等的物品按从低到高排好序,工程师发明了一种排序机械臂。它遵循一个简单的排序规则,第一次操作找到最低的物品位置P1,并把从左起第1个至第P1个之间的物品反序;第二次找到第二低的物品的位置P2,并把左起第二个至第P2个之间的物品反序……最终所有的物品都会被排好序。 

       上图给出一个示例,第一次操作前,最低物品在位置4,于是把第1至第4个物品反序;第二次操作前,第二低的物品在位置6,于是把第2至第6的物品反序…… 

  你的任务是编写一个程序,确定操作序列,即每次操作前第i低的物品所在的位置Pi,以便机械臂工作。需要注意的是,如果有高度相同的物品,必须保证排序后他们的相对位置关系与初始时相同。

Input

第一行包含一个正整数n,表示需要排序的物品数量。 
第二行包含n和空格分隔的整数ai,表示每个物品的高度。

Output

输出一行包含n个空格分隔的整数Pi。

Sample Input

样例输入1:

6

3 4 5 1 6 2

样例输入2:

4

3 3 2 1

Sample Output

样例输出1:

4 6 4 5 6 6

样例输出2:

4 2 4 4

Hint

对于30%的数据,1<=n<=1000 
对于100%的数据,1<=n<=100000,1<=ai<=2*10^9

调了一个中午,发现不能用新点表示下标。。。。

讲下思路,因为发现询问和高度没有关系,而且splay维护区间后不能同时维护第k大值,于是我们想到排序,这样就符合题目的第i大要求,但是这样做必须要求原序列下标和splay下标严格对应= =

#include<bits/stdc++.h>
using namespace std;
inline int get(){register int re=0,f=1;register char c;while(c=getchar(),(c>='0'&&c<='9')^1)f=c^'-';while(re=(re<<1)+(re<<3)+(c^48),c=getchar(),(c>='0'&&c<='9'));return f?re:-re;}
#define Inc(i,L,R) for(register int i=(L);i<=(R);++i)
#define Red(j,R,L) for(register int j=(R);j>=(L);--j)
const int N = 1e5+10;
struct Pair{
	int fir,sec;//权值,位置 
}a[N];
int n;
struct Splay{
	bool rev[N];
	int k[N],siz[N];
	int rt,cnt,p[N],ch[N][2];
	#define Ls(v) ch[v][0]
	#define rs(v) ch[v][1]
	#define sum(v) siz[v]=siz[Ls(v)]+siz[rs(v)]+1
	inline void pushdown(int x){
		if(rev[x]){
			rev[Ls(x)]^=1,rev[rs(x)]^=1;
			swap(Ls(x),rs(x));
			rev[x]=0;
		}
	}
	inline void rot(int x){
		int f=p[x],gf=p[f],type=ch[f][1]==x,son=ch[x][!type];
		ch[p[son]=f][type]=son,sum(f);
		ch[p[f]=x][!type]=f,sum(x);
		ch[p[x]=gf][ch[gf][1]==f]=x;
	}
	inline void splay(int x,bool flag){
		while(p[x]){
			if(!flag&&x==rs(rt))break;
			if(p[p[x]])pushdown(p[p[x]]);
			if(p[x])pushdown(p[x]);
			if(x)pushdown(x);
			if(flag&&p[p[x]]&&((ch[p[p[x]]][1]==p[x])==(ch[p[x]][1]==x)))rot(p[x]);
			else if(!flag&&p[x]!=rs(rt)&&((ch[p[p[x]]][1]==p[x])==(ch[p[x]][1]==x)))rot(p[x]);
			rot(x);
		}
		if(flag)rt=x;
	}
	inline int build(int L,int r){
		if(L>r)return 0;
		int Mid=L+r>>1;//用位置当下标 
		siz[Mid]=1;
		Ls(Mid)=build(L,Mid-1);
		rs(Mid)=build(Mid+1,r);
		sum(Mid);
		if(Ls(Mid))p[Ls(Mid)]=Mid;
		if(rs(Mid))p[rs(Mid)]=Mid;
		return Mid;
	}
	inline int FindP(int kth){
		int x=rt;
		while(1){
			pushdown(x);
			if(siz[Ls(x)]+1==kth)break;
			if(siz[Ls(x)]+1<kth)kth-=siz[Ls(x)]+1,x=rs(x);
			else x=Ls(x);
		}
		return x;
	}
	inline void reverse(int L,int r){
		int Lp=FindP(L),rp=FindP(r);
		splay(Lp,1),splay(rp,0);
		rev[Ls(rp)]^=1;
	}
}sp;
bool cmp(const Pair&A,const Pair&B){
	return A.fir^B.fir?A.fir<B.fir:A.sec<B.sec;
}
inline void init(){
	scanf("%d",&n);
	a[1]=(Pair){-0x3f3f3f3f,1};
	Inc(i,2,n+1)a[i]=(Pair){get(),i};
	a[n+2]=(Pair){0x3f3f3f3f,n+2};
	sort(a+1,a+n+3,cmp);
	sp.rt=sp.build(1,n+2);
}
inline void solv(){
	Inc(i,2,n+1){
		sp.splay(a[i].sec,1);//中序遍历即区间位置 
		cout<<sp.siz[sp.Ls(sp.rt)]<<' ';//哨兵的影响 
		sp.reverse(i-1,sp.siz[sp.Ls(sp.rt)]+2);//+2你懂 
	}
}
int main(){
	init();
	solv();
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值