1. 程式人生 > >HDU1890 Robotic Sort

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;
}