BZOJ_3223: Tyvj 1729 文艺平衡树 _splay

题意: 

您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1

 

分析:

splay维护区间操作的模板题。

节点维护区间信息。

提取区间:把l-1旋到根,再把r+1旋到根的右儿子,那么根的右儿子的左子树则是我们需要的区间。

建树:递归建树,左儿子还是右儿子取决于在当前区间的位置。

区间反转:打标记的思想,每个标记只对儿子生效。

其他:建两个哨兵节点来保护1和n

 

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 100050
int ch[N][2],f[N],siz[N],val[N];
int rt,sz,n,m,tag[N];
void clear(int x){ ch[x][0]=ch[x][1]=f[x]=siz[x]=val[x]=0; }
int get(int x){ return ch[f[x]][1]==x; }
void up(int x){ if(x)siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;}
void pud(int x){ if(!tag[x])return ;tag[x]=0;swap(ch[x][0],ch[x][1]);tag[ch[x][0]]^=1;tag[ch[x][1]]^=1; }
void rotate(int x)
{
    int y=f[x],z=f[y],k=get(x);
    ch[y][k]=ch[x][k^1];f[ch[y][k]]=y;ch[x][k^1]=y;f[y]=x;f[x]=z;
    if(z) ch[z][ch[z][1]==y]=x; up(y),up(x);
    if(rt==y)rt=x;
}
void splay(int x,int y)
{
    for(int fa;(fa=f[x])!=y;rotate(x))
        if(f[fa]!=y)
            rotate((get(x)==get(fa)) ? fa : x);
}
int find(int x)
{
    int now=rt;
    while(1)
    {
        pud(now);
        if(x<=siz[ch[now][0]])now=ch[now][0];
        else
        {
            x-=siz[ch[now][0]]+1;
            if(!x)return now;
            now=ch[now][1];
        }
    }
}
void build(int fa,int l,int r)
{
    if(l>r)return ;
    int mid = l + r >> 1;
    ch[fa][mid > fa] = mid;
    siz[mid] = 1;
    val[mid] = mid - 1;
    f[mid] = fa;
    build(mid, l, mid - 1);
    build(mid, mid + 1, r);
    up(mid);
}
void reverse(int x,int y)
{
    x=find(x);
    y=find(y);
    splay(x,f[rt]);
    splay(y,rt);    
    tag[ch[y][0]]^=1;
}
int main()
{
    scanf("%d%d", &n, &m);
    int i,x,y;
    build(0,1,n+2);
    rt=n+3>>1;
    for(i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        reverse(x,y+2);
    }
    for(i=2;i<=n;i++) printf("%d ",val[find(i)]);
    printf("%d",val[find(n+1)]);
}

 

posted @ 2018-03-17 21:32  fcwww  阅读(141)  评论(0编辑  收藏  举报