P3391 【模板】文艺平衡树(Splay) 平衡树

  

题目背景

这是一道经典的Splay模板题——文艺平衡树。

题目描述

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

输入格式

第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2, \cdots n-1,n)(1,2,⋯n−1,n) m表示翻转操作次数

接下来m行每行两个数 [l,r][l,r] 数据保证 1 \leq l \leq r \leq n1≤l≤r≤n

输出格式

输出一行n个数字,表示原始序列经过m次变换后的结果

输入输出样例

输入 #1
5 3
1 3
1 3
1 4
输出 #1
4 3 2 1 5


这题搞了好久 把权值平衡树和区间平衡树搞混了

这题看似翻转了 其BST性质被破坏了 其实没有 下标仍然保持BST性质 只是val交换了


在最左和右分别插入一个值 方便维护

翻转时
l=kth(l);r=kth(r+2); 那么根结点的右儿子的左子树就是序列 l-r

P3391 【模板】文艺平衡树(Splay)  平衡树
#include<bits/stdc++.h>
using namespace std;
//input by bxd
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);--i)
#define ll long long
#define see(x) (cerr<<(#x)<<'='<<(x)<<endl)
#define pb push_back
#define inf 0x3f3f3f3f
#define CLR(A,v)  memset(A,v,sizeof A)
typedef pair<int,int>pii;
//////////////////////////////////
const int N=2e6+10;


int son[N][2],fa[N],siz[N],cnt[N],val[N],ncnt,root,col[N],n,m;


int chk(int x)
{
    return son[fa[x]][1]==x;
}
void up(int x)
{
    siz[x]=siz[son[x][1]]+siz[son[x][0]]+cnt[x];
}
void down(int x)
{
    if(col[x])
    {
        col[son[x][0]]^=1;
        col[son[x][1]]^=1;
        col[x]=0;
        swap(son[x][0],son[x][1]);
    }
}
void rotate(int x)
{
    int y=fa[x],z=fa[y],k=chk(x),w=son[x][k^1];
    son[y][k]=w;fa[w]=y;
    son[z][chk(y)]=x;fa[x]=z;
    son[x][k^1]=y;fa[y]=x;
    up(x);up(y);
}

void splay(int x,int goal=0)
{
    while(fa[x]!=goal)
    {
        int y=fa[x],z=fa[y];
        if(z!=goal)
        {
            if(chk(y)==chk(x))rotate(y);
            else rotate(x);
        }
        rotate(x);
    }
    if(!goal)root=x;
}
void insert(int x)
{
    int pos=root,p=0;
    while(pos&&val[pos]!=x)p=pos,pos=son[pos][x>val[pos]];
    if(pos)cnt[pos]++;
    else
    {
        pos=++ncnt;
        if(p)son[p][x>val[p]]=pos;
        son[pos][0]=son[pos][1]=0;
        cnt[pos]=siz[pos]=1;
        val[pos]=x;fa[pos]=p;
    }
    splay(pos);
}
int kth(int k)
{
    int pos=root;
    while(1)
    {
        down(pos);
        if(son[pos][0]&&siz[son[pos][0]]>=k)pos=son[pos][0];
        else if(k>siz[son[pos][0]]+cnt[pos])k-=siz[son[pos][0]]+cnt[pos],pos=son[pos][1];
        else {splay(pos);return pos;}
    }
}
void output(int x)
{
    down(x);
    if(son[x][0])output(son[x][0]);
    if(val[x]>1&&val[x]<n+2)printf("%d ",val[x]-1);
    if(son[x][1])output(son[x][1]);
}
void work(int l,int r)
{
   // printf("aaa");
    l=kth(l);r=kth(r+2);
   // printf("vall=%d valr=%d\n",val[l],val[r]);
    splay(l);splay(r,l);
    col[son[son[root][1]][0]]^=1;
}
int main()
{
    scanf("%d%d",&n,&m);
    rep(i,1,n+2)insert(i);
    while(m--)
    {
        int l,r;scanf("%d%d",&l,&r);
        work(l,r);
    }
    output(root);
}
View Code


上一篇:洛谷 P3391 【模板】文艺平衡树(Splay)


下一篇:Luogu P3391 【模板】文艺平衡树 Splay 平衡树