题目描述
输入
输入共两行,第一行为一个整数N,N表示物品的个数,1<=N<=100000。
第二行为N个用空格隔开的正整数,表示N个物品最初排列的编号。
输出
输出共一行,N个用空格隔开的正整数P1,P2,P3…Pn,Pi表示第i次操作前第i小的物品所在的位置。
注意:如果第i次操作前,第i小的物品己经在正确的位置Pi上,我们将区间[Pi,Pi]反转(单个物品)。
样例输入
6
3 4 5 1 6 2
3 4 5 1 6 2
样例输出
4 6 4 5 6 6
非旋转treap练习题。题目要求每次找到第i小的Pi并将i~Pi翻转,因为在第i次操作时,前i小的数在最前面不会被翻转,之后也不会被用到。那么我们可以对序列建非旋转treap每次找到最小的,然后删除掉它,再将它原位置之前的部分翻转即可。但发现不能只维护子树最小值,因为有相同值时要选编号小的,也不能有多个最小值优先遍历左子树,因为原先编号小的翻转后可能成了右子树。所以我们先将原序列排个序,按排序后的顺序作为他们新的权值,再按原顺序插入treap,这样每个点的权值就是独一无二的了,直接记录最小值每次查找即可。不要忘记查找时也要下传翻转标记。
#include<set> #include<map> #include<stack> #include<queue> #include<cmath> #include<cstdio> #include<vector> #include<bitset> #include<cstring> #include<iostream> #include<algorithm> #define ll long long using namespace std; int n; int cnt; int root; int x,y,z; int v[100010]; int s[100010]; int r[100010]; int mn[100010]; int ls[100010]; int rs[100010]; int size[100010]; struct miku { int val; int num; int rak; }a[100010]; bool cmp1(miku a,miku b) { if(a.val!=b.val) { return a.val<b.val; } return a.num<b.num; } bool cmp2(miku a,miku b) { return a.num<b.num; } int build(int val) { int rt=++cnt; r[rt]=rand(); v[rt]=val; mn[rt]=val; size[rt]=1; return rt; } void rotate(int rt) { swap(ls[rt],rs[rt]); s[rt]^=1; } void pushup(int rt) { size[rt]=size[ls[rt]]+size[rs[rt]]+1; mn[rt]=v[rt]; if(ls[rt]) { mn[rt]=min(mn[rt],mn[ls[rt]]); } if(rs[rt]) { mn[rt]=min(mn[rt],mn[rs[rt]]); } } void pushdown(int rt) { if(s[rt]) { if(ls[rt]) { rotate(ls[rt]); } if(rs[rt]) { rotate(rs[rt]); } s[rt]^=1; } } int merge(int x,int y) { if(!x||!y) { return x+y; } pushdown(x); pushdown(y); if(r[x]<r[y]) { rs[x]=merge(rs[x],y); pushup(x); return x; } else { ls[y]=merge(x,ls[y]); pushup(y); return y; } } void split(int rt,int k,int &x,int &y) { if(!rt) { x=y=0; return ; } pushdown(rt); if(size[ls[rt]]<k) { x=rt; split(rs[rt],k-size[ls[rt]]-1,rs[x],y); } else { y=rt; split(ls[rt],k,x,ls[y]); } pushup(rt); } int rank(int rt) { pushdown(rt); int res=v[rt]; if(ls[rt]) { res=min(res,mn[ls[rt]]); } if(rs[rt]) { res=min(res,mn[rs[rt]]); } if(res==mn[ls[rt]]) { return rank(ls[rt]); } else if(res==v[rt]) { return size[ls[rt]]+1; } else { return size[ls[rt]]+1+rank(rs[rt]); } } int main() { srand(20020419); scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i].val); a[i].num=i; } sort(a+1,a+1+n,cmp1); for(int i=1;i<=n;i++) { a[i].rak=i; } sort(a+1,a+1+n,cmp2); for(int i=1;i<=n;i++) { root=merge(root,build(a[i].rak)); } for(int i=1;i<=n;i++) { int ans=rank(root); printf("%d",i-1+ans); if(i!=n) { printf(" "); } split(root,ans-1,x,y); split(y,1,y,z); rotate(x); root=merge(x,z); } }