bzoj 1552(splay)

来源:互联网 发布:网络话费充值卡怎么用 编辑:程序博客网 时间:2024/05/20 16:36

1552: [Cerc2007]robotic sort

Time Limit: 5 Sec  Memory Limit: 64 MB
Submit: 681  Solved: 278
[Submit][Status][Discuss]

Description

Input

输入共两行,第一行为一个整数N,N表示物品的个数,1<=N<=100000。第二行为N个用空格隔开的正整数,表示N个物品最初排列的编号。

Output

输出共一行,N个用空格隔开的正整数P1,P2,P3…Pn,(1 < = Pi < = N),Pi表示第i次操作前第i小的物品所在的位置。 注意:如果第i次操作前,第i小的物品己经在正确的位置Pi上,我们将区间[Pi,Pi]反转(单个物品)。

Sample Input

6
3 4 5 1 6 2

Sample Output

4 6 4 5 6 6


解题思路:splay的裸题,每个点记入下它子树的最小值,然后splay维护翻转和选择区间


#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n,sum,ug,mx,root;
int a[110000];
int zhi[110000],dui[110000],pan[110000],qo[110000],size[110000],fa[110000],l[110000],r[110000],rever[110000];
int po[110000],q[110000];


inline int read()
{
char y; int x=0,f=1; y=getchar();
while (y<'0' || y>'9') {if (y=='-') f=-1; y=getchar();}
while (y>='0' && y<='9') {x=x*10+int(y)-48; y=getchar();}
return x*f;
}


void build(int &x,int lg,int rg,int f)
 {
  int mid=(lg+rg)/2;
  x=mid;
  zhi[mid]=a[mid]; dui[mid]=mid; pan[mid]=mid; qo[mid]=zhi[mid]; size[mid]=rg-lg+1; fa[mid]=f;
  if (lg==rg) return;
    if (lg<=mid-1) build(l[x],lg,mid-1,mid);
    if (mid+1<=rg) build(r[x],mid+1,rg,mid);
    int u; if (qo[l[x]]<qo[r[x]]||(qo[l[x]]==qo[r[x]] && dui[pan[l[x]]]<dui[pan[r[x]]])){u=pan[l[x]];}else u=pan[r[x]];
    if (qo[u]<qo[pan[mid]] || (qo[u]==qo[pan[mid]] && dui[u]<dui[pan[mid]]))
     {
      pan[mid]=u; qo[mid]=qo[u];
}
 }
 
void pushdown(int now)
{
if (rever[now]==1)
{
rever[now]^=1; 
if (l[now]!=0) rever[l[now]]^=1;
if (r[now]!=0) rever[r[now]]^=1;
swap(l[now],r[now]);

 }  


void find(int now,int zhi)
 {
  pushdown(now);
  if (zhi==now)
  {
  sum+=size[l[now]]+1;
  return;
 }
if (pan[l[now]]==zhi)
     {
      find(l[now],zhi);
}else
 {
  sum+=size[l[now]]+1;
  find(r[now],zhi);
 }
 } 
 
int find1(int now,int sug)
 {
  pushdown(now);
  if (sug==size[l[now]]+1) return now;
  if (sug>size[l[now]]+1) return find1(r[now],sug-size[l[now]]-1);else return find1(l[now],sug);
 }


 
void maindown(int now)
 {
  size[now]=size[l[now]]+size[r[now]]+1;
  pan[now]=now; qo[now]=zhi[now];
  int u; if (qo[pan[l[now]]]<qo[pan[r[now]]]||(qo[pan[l[now]]]==qo[pan[r[now]]] && dui[pan[l[now]]]<dui[pan[r[now]]])){u=pan[l[now]];}else u=pan[r[now]];
    if (qo[u]<qo[pan[now]] || (qo[u]==qo[pan[now]] && dui[u]<dui[pan[now]]))
     {
      pan[now]=u; qo[now]=qo[u];
}
  } 
 
void rotate(int x,int &mu) 
 {
  int y=fa[x]; int z=fa[y];
  if (y==mu) mu=x;else
  {
  if (l[z]==y) l[z]=x; else r[z]=x;
 }
fa[y]=x; fa[x]=z;
if (l[y]==x)
{
fa[r[x]]=y; l[y]=r[x]; r[x]=y; 
}else
 {
   fa[l[x]]=y; r[y]=l[x]; l[x]=y; 
 }
    maindown(y); maindown(x);
 }
 
void splay(int x,int &mu)
 {
  int now=x; int tail=0;
  while(now!=mu)
  {
  ++tail; q[tail]=now; now=fa[now];
 } pushdown(now);
for (int i=tail;i>=1;--i) pushdown(q[i]);
  while (x!=mu)
  {
  int y=fa[x]; int z=fa[y];
  if (y!=mu)
  {
    if (l[y]==x ^ l[z]==y) rotate(x,mu);else
 rotate(y,mu); 
}
rotate(x,mu);
}
 }
 
int main()
{
n=read(); a[1]=0x7fffffff; a[n+2]=0x7fffffff; a[0]=0x7fffffff; qo[0]=0x7fffffff; 
for (int i=1;i<=n;++i)
{
a[i+1]=read();
}
n=n+2;
build(root,1,n,0);
for (int i=1;i<=n-2;++i)
{
if (i==n-2)
{
printf("%d",n-2);
return(0);
}
ug=find1(root,i);
splay(ug,root); 
sum=0; 
find(root,pan[r[root]]); ug=find1(root,sum+1);
printf("%d ",sum-1);
splay(ug,r[root]);
splay(pan[r[root]],l[r[root]]);
rever[l[r[root]]]^=1;
}
}

0 0