procedure2012
It's not worth it to know you're not worth it!

[关键字]:数据结构 Splay

[题目大意] :有一个数字序列,按照如下顺序进行排序:在第i次交换时找到第i小的数字所在的位置k然后将[i,k]区间反转。问第i次反转前第i小的数字所在的位置。

//==============================================================================================

[分析]:既要支持反转操作又要快速查找的数据结构一定是——伸展树!但一开始我没想好怎么用,为了维护序列的顺序必须以原序列下标为关键字建立Splay,但是这样就无法快速查找第i小的数的位置,然后我就冥思苦想了一天发现自己二了……可以这样:一原序列下标为关键字建立Splay但是树的节点编号为此位置上的值是第几小。这样,每次就可以维护好Splay然后直接就可求出第i小的值的位置:它所在的节点的左子树大小+1,因为它将被置于前面不会被再次反转,为了方便可以将这个点删掉,没必要真删,只要将它所在子树大小-1,它的dat变成0。注意的是更新的顺序,自底向上更新子树大小时要先更新下面再更新上面,而传递反转的bool标记要先更新上面再更新下面。

[代码]:

View Code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const int INF=0x7fffffff;
const int MAXN=110000;

struct node
{
int dat,size,c[2],f;
bool rev;
}tree[MAXN];
int N,root=0,tn=0;
int p[MAXN],a[MAXN],b[MAXN];

void Downdate(int v)
{
if (!v || !tree[v].rev) return ;
tree[v].rev=0;
tree[tree[v].c[0]].rev=!tree[tree[v].c[0]].rev;
tree[tree[v].c[1]].rev=!tree[tree[v].c[1]].rev;
//swap(tree[v].c[0],tree[v].c[1]);
int t=tree[v].c[0];
tree[v].c[0]=tree[v].c[1],tree[v].c[1]=t;
}

void Update(int v)
{
if (!v) return ;
//printf("%d %d)))\n",tree[6].c[0],tree[6].c[1]);
tree[v].size=tree[tree[v].c[0]].size+tree[tree[v].c[1]].size+tree[v].dat;
//printf("%d %d %d %d %d %d***\n",v,tree[v].size,tree[v].c[0],tree[v].c[1],tree[tree[v].c[0]].size,tree[tree[v].c[1]].size);
}

void rotate(int x,int o)
{
int y=tree[x].f;
tree[y].c[o]=tree[x].c[!o];
tree[tree[y].c[o]].f=y;
tree[x].f=tree[y].f;
if (tree[tree[y].f].c[0]==y)
tree[tree[y].f].c[0]=x;
else
tree[tree[y].f].c[1]=x;
tree[y].f=x;
tree[x].c[!o]=y;
if (root==y) root=x;
Update(y);
Update(x);
}

void Splay(int x,int y)
{
while (tree[x].f!=y)
{
Downdate(tree[tree[x].f].f);
Downdate(tree[x].f);
Downdate(x);
if (tree[tree[x].f].f==y)
{
if (tree[tree[x].f].c[0]==x)
rotate(x,0);
else
rotate(x,1);
} else if (tree[tree[tree[x].f].f].c[0]==tree[x].f)
{
if (tree[tree[x].f].c[0]==x)
rotate(tree[x].f,0),rotate(x,0);
else
rotate(x,1),rotate(x,0);
}
else
{
if (tree[tree[x].f].c[1]==x)
rotate(tree[x].f,1),rotate(x,1);
else
rotate(x,0),rotate(x,1);
}
}
//Update(x);
}

void debug(int v)
{
//Downdate(v);
//Update(v);
if (tree[v].c[0]) debug(tree[v].c[0]);
printf("%d %d %d %d %d %d\n",v,tree[v].c[0],tree[v].c[1],tree[v].size,tree[v].f,tree[v].dat);
if (tree[v].c[1]) debug(tree[v].c[1]);
//Update(v);
}

int Find(int v)
{
int pos;
Splay(v,0);
//Update(v);
//printf("%d\n",root);
//debug(root);
//printf("\n/8/==================\n");
if (tree[v].c[0])
{
pos=tree[tree[v].c[0]].size+1;
tree[tree[v].c[0]].rev=!tree[tree[v].c[0]].rev;
}
else pos=1;
tree[v].dat=0;
tree[v].size--;
return pos;
}

int main()
{
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
scanf("%d",&N);
for (int i=1;i<=N;i++) scanf("%d",&a[i]),p[a[i]]=i;
sort(a+1,a+N+1);
for (int i=1;i<=N;i++) b[p[a[i]]]=i;
//for (int i=1;i<=N;i++) printf("%d ",b[i]);
//printf("\n");
for (int i=1;i<=N;i++)
{
tree[b[i]].size=i;
tree[b[i]].rev=0;
tree[b[i]].dat=1;
tree[b[i]].c[0]=i>1?b[i-1]:0;
tree[b[i]].c[1]=0;
tree[b[i]].f=i<N?b[i+1]:0;
}
root=b[N];
//debug(N);
//for (int i=1;i<=N;i++) printf("%d %d %d %d\n",b[i],tree[b[i]].c[0],tree[b[i]].c[1],tree[b[i]].f);
//printf("%d\n",root);
for (int j=1;j<=N;j++)
{
//debug(root);
//printf("\n//==================\n");
//for (int i=1;i<=N;i++) printf("%d %d %d %d %d\n",b[i],tree[b[i]].c[0],tree[b[i]].c[1],tree[b[i]].f,tree[b[i]].rev);
printf("%d ",Find(j)+j-1);
}
printf("\n");
return 0;
}



posted on 2012-02-27 23:01  procedure2012  阅读(257)  评论(0编辑  收藏  举报