bzoj 3223 Tyvj 1729 文艺平衡树 Splay

26 篇文章 0 订阅
4 篇文章 0 订阅

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3223

题解:Splay区间翻转,用一个数组rev作标记,如果rev=1,那么就将其左右儿子交换,并将rev向其左右儿子传递,这样就可以实现区间翻转。

Code
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 100010
using namespace std;
int n,m,root;
int ls[N],rs[N],s[N],v[N],f[N],rev[N];

void PushUp(int k)
{
    s[k]=s[ls[k]]+s[rs[k]]+1;
}

void PushDown(int k)
{
    if(!rev[k])return ;
    swap(ls[k],rs[k]);
    rev[ls[k]]^=1,rev[rs[k]]^=1;
    rev[k]=0;
}

void zig(int x)
{
    int y=f[x],z=f[y];
    if(ls[z]==y)ls[z]=x;
    else rs[z]=x;
    f[x]=z,f[y]=x,ls[y]=rs[x],f[rs[x]]=y,rs[x]=y;
    PushUp(y),PushUp(x);
    if(y==root)root=x;
}

void zag(int x)
{
    int y=f[x],z=f[y];
    if(ls[z]==y)ls[z]=x;
    else rs[z]=x;
    f[x]=z,f[y]=x,rs[y]=ls[x],f[ls[x]]=y,ls[x]=y;
    PushUp(y),PushUp(x);
    if(y==root)root=x;
}

void Splay(int x,int k)
{
    while(f[x]!=k)
    {
        int y=f[x];
        if(ls[y]==x)zig(x);
        else zag(x);
    }
}

int find(int &k,int x)
{
    PushDown(k);
    if(s[ls[k]]+1==x)return k;
    if(s[ls[k]]>=x)return find(ls[k],x);
    return find(rs[k],x-s[ls[k]]-1);
}

void build(int l,int r,int fa)
{
    if(l>r)return ; 
    int now=v[l],last=v[fa];
    if(l==r)
    {
        s[now]=1;
        f[now]=last;
        if(l<fa)ls[last]=now;
        else rs[last]=now;
        return ;
    }
    int mid=(l+r)>>1;
    now=v[mid];
    build(l,mid-1,mid);
    build(mid+1,r,mid);
    f[now]=last;
    if(mid<fa)ls[last]=now;
    else rs[last]=now;
    PushUp(mid);
}

void rever(int l,int r)
{
    int x=find(root,l);
    int y=find(root,r);
    Splay(x,0);
    Splay(y,x);
    rev[ls[y]]^=1;
}

int main()
{
    cin>>n>>m;
    for(int i=1;i<=n+2;i++)v[i]=i;
    root=(n+3)>>1;
    build(1,n+2,0);
    for(int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        rever(x,y+2);
    }
    for(int i=2;i<=n+1;i++)printf("%d ",find(root,i)-1);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值