HDU1890 Robotic Sort(伸展树换根+删除操作)
【题目描述】
Somewhere deep in the Czech Technical University buildings, there are laboratories for examining mechanical and electrical properties of various materials. In one of yesterday’s presentations, you have seen how was one of the laboratories changed into a new multimedia lab. But there are still others, serving to their original purposes.
在捷克技术大学大楼的深处,有实验室用来检查各种材料的机械和电气性能。在昨天的一次演示中,您已经看到了一个实验室是如何变成一个新的多媒体实验室的。但还有其他实验室,服务于它们的原始目的。
In this task, you are to write software for a robot that handles samples in such a laboratory. Imagine there are material samples lined up on a running belt. The samples have different heights, which may cause troubles to the next processing unit. To eliminate such troubles, we need to sort the samples by their height into the ascending order.
在这项任务中,你要为一个在实验室处理样本的机器人编写软件。想象一下,跑道上有一些材料样本排列在一起。样品具有不同的高度,这可能会给下一个处理单元带来麻烦。为了消除这种麻烦,我们需要把样品按高度分类成升序。
Reordering is done by a mechanical robot arm, which is able to pick up any number of consecutive samples and turn them round, such that their mutual order is reversed. In other words, one robot operation can reverse the order of samples on positions between A and B.
重新排序由机械机械手臂完成,机械手臂能够拾取任意数量的连续样本并将其旋转,使得它们的相互顺序相反。换句话说,一个机器人操作可以颠倒A和B之间位置上的样本顺序。
A possible way to sort the samples is to find the position of the smallest one (P1) and reverse the order between positions 1 and P1, which causes the smallest sample to become first. Then we find the second one on position P and reverse the order between 2 and P2. Then the third sample is located etc.
对样本进行排序的一种可能的方法是找到最小样本(P1)的位置,并将位置1和P1之间的顺序颠倒,这导致最小样本成为第一。然后在位置P上找到第二个,并反转2和P2之间的顺序。然后定位第三个样本等。
The picture shows a simple example of 6 samples. The smallest one is on the 4th position, therefore, the robot arm reverses the first 4 samples. The second smallest sample is the last one, so the next robot operation will reverse the order of five samples on positions 2–6. The third step will be to reverse the samples 3–4, etc.
图中显示了6个样本的简单例子。最小的一个在第四个位置,因此,机械臂反转前4个样本。第二个最小样本是最后一个,所以下一个机器人操作将颠倒位置2-6的五个样本的顺序。第三个步骤是反转样本3—4等。
Your task is to find the correct sequence of reversal operations that will sort the samples using the above algorithm. If there are more samples with the same height, their mutual order must be preserved: the one that was given first in the initial order must be placed before the others in the final order too.
你的任务是找到正确的反转操作序列,使用上述算法对样本进行排序。如果有更多的样品具有相同的高度,它们必须保持相互的顺序:在初始顺序中首先给出的样品也必须在最终顺序中放在其他样品之前。(翻译来自度娘)
【输入格式】
多组数据,每组数据包括两行,第一行为整数N,第二行为N个整数,即单个样品高度和初始位置,最后一组为0。
【输出格式】
每组数据输出N个整数表示第i次反转前第i大的位置。
【样例输入】
6
3 4 5 1 6 2
4
3 3 2 1
0
【样例输出】
4 6 4 5 6 6
4 2 4 4
【题目分析】
Splay板题吧。
首先,将整段序列按照相对位置不变建立伸展树(即重载运算符时如果高度一样就返回id较小的那个),维护每个节点左右孩子的个数。每次回答就是进行一次Splay操作,将目标转移到根,它左子树的结点个数就是它在原序列中的位置。反转操作就是区间反转。
【代码~】
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int MAXN=5e5+10;
const int INF=0x3f3f3f3f;
#define lc (tr[id].c[0])
#define rc (tr[id].c[1])
#define KEY tr[tr[root].c[1]].c[0]
int data[MAXN/5];
struct Num{
int val,id;
bool operator<(const Num &a)const{
if(val==a.val)
return id<a.id;
return val<a.val;
}
}So[MAXN/5];
struct Tr{
int fa,sum;
int val,c[2],lz;
}tr[MAXN];
int tot,root,n;
int newtr(int k,int f,int pos)
{
tr[tot].sum=1,tr[tot].val=k;
tr[tot].c[0]=tr[tot].c[1]=-1;
tr[tot].lz=0;
tr[tot].fa=f;
return tot++;
}
void Push(int id)
{
int lsum,rsum;
lsum=(lc==-1)?0:tr[lc].sum;
rsum=(rc==-1)?0:tr[rc].sum;
tr[id].sum=lsum+rsum+1;
}
int build(int l,int r,int f)
{
if(r<l)
return -1;
int mid=l+r>>1;
int ro=newtr(mid,f,mid);
data[mid]=ro;
tr[ro].c[0]=build(l,mid-1,ro);
tr[ro].c[1]=build(mid+1,r,ro);
Push(ro);
return ro;
}
void lazy(int id)
{
if(tr[id].lz)
{
swap(lc,rc);
tr[lc].lz^=1,tr[rc].lz^=1;
tr[id].lz=0;
}
}
void Rotate(int x,int k)
{
if(tr[x].fa==-1)
return ;
int fa=tr[x].fa,w;
lazy(fa);
lazy(x);
tr[fa].c[!k]=tr[x].c[k];
if(tr[x].c[k]!=-1)
tr[tr[x].c[k]].fa=fa;
tr[x].fa=tr[fa].fa,tr[x].c[k]=fa;
if(tr[fa].fa!=-1)
{
w=tr[tr[fa].fa].c[1]==fa;
tr[tr[fa].fa].c[w]=x;
}
tr[fa].fa=x;
Push(fa);
Push(x);
}
void Splay(int x,int goal)
{
if(x==-1)
return ;
lazy(x);
while(tr[x].fa!=goal)
{
int y=tr[x].fa;
lazy(tr[y].fa);
lazy(y),lazy(x);
bool w=x==tr[y].c[1];
if(tr[y].fa!=goal&&w==(y==tr[tr[y].fa].c[1]))
Rotate(y,!w);
Rotate(x,!w);
}
if(goal==-1)
root=x;
Push(x);
}
int find(int k)
{
int id=root;
while(id!=-1)
{
lazy(id);
int lsum=(lc==-1)?0:tr[lc].sum;
if(lsum>=k)
{
id=lc;
}
else
if(lsum+1==k)
break;
else
{
k=k-lsum-1;
id=rc;
}
}
return id;
}
int Getnext(int id)
{
lazy(id);
int p=tr[id].c[1];
if(p==-1)
return id;
lazy(p);
while(tr[p].c[0]!=-1)
{
p=tr[p].c[0];
lazy(p);
}
return p;
}
int main()
{
int m,l,r,k,d,i;
while(~scanf("%d",&n),n)
{
for(i=1;i<=n;++i)
{
scanf("%d",&So[i].val);
So[i].id=i;
}
sort(So+1,So+n+1);
So[0].id=0;
tot=0;
root=build(0,n+1,-1);
for(i=1;i<=n;++i)
{
int ro=data[So[i].id],ne;
Splay(ro,-1);
d=tr[tr[root].c[0]].sum;
l=data[So[i-1].id];
ne=Getnext(ro);
Splay(l,-1);
Splay(ne,root);
lazy(root);
lazy(tr[root].c[1]);
tr[KEY].lz^=1;
if(i!=1)
printf(" ");
printf("%d",d);
}
puts("");
}
return 0;
}