前言
适合入门但其实不算很裸的平衡树题
题目
讲解
在做这道题之前,最好先康康这道更板的题:
对于这道题,模拟就完事了
我使用平衡树是(Splay)
这道题的难点就在如何快速找到排名第(i)个数的位置
至于(reverse)操作,在板题中应该已经熟悉了
其实很简单,只需要将每个数与其对应在(Splay)上的点的编号记录下来,当你需要找到它的位置的时候,将它(splay)到根即可,它的位置就是左儿子大小+1
注意我们插入的(1)与(n+2)两个哨兵对各种造成的影响
同时注意输出格式,末尾不能有多余空格
代码
int ID[MAXN];
struct number
{
int x,pos;
}num[MAXN];
bool cmp1(number a,number b)
{
if(a.x != b.x) return a.x < b.x;
return a.pos < b.pos;
}
bool cmp2(number a,number b)
{
return a.pos < b.pos;
}
#define lc t[x].ch[0]
#define rc t[x].ch[1]
struct Splay
{
int tot,rt;//点,根
struct node
{
int ch[2],val,f,siz,cnt;//儿子,value,父亲,size,count
bool fz;//翻转标记
}t[MAXN];
int newnode(int fa,int val)
{
++tot;
t[tot].ch[0] = t[tot].ch[1] = 0;
t[tot].siz = t[tot].cnt = 1;
t[tot].val = val;
t[tot].f = fa;
t[tot].fz = 0;
return tot;
}
bool chk(int x)//判断是左儿子还是右儿子
{
return t[t[x].f].ch[1] == x;
}
void up(int x)
{
t[x].siz = t[lc].siz + t[rc].siz + t[x].cnt;
}
void down(int x)
{
if(!t[x].fz) return;
t[x].fz = 0;
t[lc].fz ^= 1;
t[rc].fz ^= 1;
swap(lc,rc);
}
int Build(int fa,int l,int r)
{
if(l > r) return 0;
int mid = (l+r) >> 1;
int x = newnode(fa,num[mid].x);
ID[num[mid].x] = x;//记录对应在平衡树上点的编号
lc = Build(x,l,mid-1);rc = Build(x,mid+1,r);
up(x);
return x;
}
void rotate(int x)
{
down(t[x].f);down(x);
int y = t[x].f,z = t[t[x].f].f;
bool cz = chk(y),cy = chk(x);
t[x].f = z; t[z].ch[cz] = x;
t[y].ch[cy] = t[x].ch[cy^1]; t[t[x].ch[cy^1]].f = y;
t[x].ch[cy^1] = y; t[y].f = x;
up(y);up(x);
}
void splay(int x,int to = 0)
{
while(t[x].f != to)
{
int y = t[x].f,z = t[t[x].f].f;
if(z != to)//双旋
{
if(chk(x) == chk(y)) rotate(y);
else rotate(x);
}
rotate(x);
}
if(!to) rt = x;//记得改根
}
int kth(int k)
{
int x = rt;
while(1)
{
down(x);
if(t[lc].siz >= k) x = lc;
else if(t[lc].siz + t[x].cnt < k) k -= t[lc].siz + t[x].cnt,x = rc;
else return x;
}
}
void reverse(int l,int r)
{
if(l == r) return;
l = kth(l-1);r = kth(r+1);
splay(l);splay(r,l);
t[t[r].ch[0]].fz ^= 1;
}
void print(int x)
{
if(!x) return;
down(x);
print(lc);
Put(t[x].val,'
');
print(rc);
}
}S;
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
while(~scanf("%d",&n) && n)
{
S.tot = 0;
for(int i = 2;i <= n+1;++ i)
num[i].x = Read(),num[i].pos = i;
sort(num+2,num+n+2,cmp1);
num[1].pos = 1;num[n+2].pos = n+2;
for(int i = 1;i <= n+2;++ i)
num[i].x = i;
sort(num+1,num+n+3,cmp2);
S.rt = S.Build(0,1,n+2);
for(int i = 2;i <= n+1;++ i)
{
S.splay(ID[i]);
int pos = S.t[S.t[S.rt].ch[0]].siz;
Put(pos);
if(i == n+1) putchar('
');
else putchar(' ');
S.reverse(i,pos+1);
}
}
return 0;
}