BZOJ 3223 Tyvj 1729 文艺平衡树

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


【题目分析】
其他题目:你需要。。。。
这道题目:您需要。。。。
BZOJ抄题抄的好霸气。
Splay+区间翻转标记即可(Splay比Treap好写系列)
忘了,这题也是从隔壁SilverNebula那里找的,%。


【代码】

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>

#include <set>
#include <map>
#include <string>
#include <algorithm>
#include <vector>
#include <iostream>
#include <queue>

using namespace std;

#define maxn 1000005
#define inf (0x3f3f3f3f)

int read()
{
    int x=0,f=1; char ch=getchar();
    while (ch<'0'||ch>'9') {if (ch=='-') f=-1; ch=getchar();}
    while (ch>='0'&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}

int n,m,l,r;
int fa[maxn],ch[maxn][2],num[maxn],siz[maxn],rev[maxn],rt,tot,a[maxn];

void update(int k)
{
    siz[k]=siz[ch[k][0]]+siz[ch[k][1]]+1;
}

int build(int l,int r,int lst)
{
    if (l>r) return 0;
    int k=++tot;
//  printf("%d %d - %d\n",k,l,r);
    fa[k]=lst;
    if (l==r)
    {
        ch[k][0]=ch[k][1]=0;
        siz[k]=1;
        rev[k]=0;
        num[k]=a[l];
        return k;
    }
    int mid=(l+r)/2;
    rev[k]=0;
    num[k]=a[mid];
    ch[k][0]=build(l,mid-1,k);
    ch[k][1]=build(mid+1,r,k);
    update(k);
    return k;
}

void rot(int x,int &k)
{
//  printf("rot");
    int y=fa[x],z=fa[y],l,r;
    if (ch[y][0]==x) l=0; else l=1;
    r=l^1;
    if (y==k) k=x;
    else
    {
        if (ch[z][0]==y) ch[z][0]=x;
        else ch[z][1]=x;
    }
    fa[x]=z; fa[y]=x; fa[ch[x][r]]=y;
    ch[y][l]=ch[x][r]; ch[x][r]=y;
    update(y); update(x);
}

void pushdown(int k)
{
    if (rev[k])
    {
        rev[k]^=1;
        rev[ch[k][0]]^=1;
        rev[ch[k][1]]^=1;
        swap(ch[k][0],ch[k][1]);
    }
}

void splay(int x,int &k)
{
//  printf("sp\n");
    while (x!=k)
    {
        int y=fa[x],z=fa[y];
        if (y!=k)
        {
            if (ch[y][0]==x^ch[z][0]==y) rot(y,k);
            else rot(x,k);
        }
        rot(x,k);
    }
}

int find(int k,int x)
{
    pushdown(k);
    if (siz[ch[k][0]]+1==x) return k;
    else if (x<=siz[ch[k][0]]) return find(ch[k][0],x);
    else return find(ch[k][1],x-siz[ch[k][0]]-1);
}

void dfs(int k)
{
    pushdown(k);
    if (!k)return ;
    dfs(ch[k][0]);
    if (num[k]!=0)
    printf("%d ",num[k]);
    dfs(ch[k][1]);
}

int main()
{
    n=read();m=read();
    for (int i=1;i<=n;++i) a[i+1]=i;
    rt=build(1,n+2,0);
//  printf("rt is %d\n",rt);
    while (m--)
    {
//      for (int i=1;i<=n+2;++i) printf("%d ",i); printf("\n");
//      for (int i=1;i<=n+2;++i) printf("%d ",ch[i][0]); printf("\n");
//      for (int i=1;i<=n+2;++i) printf("%d ",ch[i][1]); printf("\n");
//      for (int i=1;i<=n+2;++i) printf("%d ",fa[i]); printf("\n");
//      for (int i=1;i<=n+2;++i) printf("%d ",num[i]); printf("\n");
//      for (int i=1;i<=n+2;++i) printf("%d ",rev[i]); printf("\n");
//      dfs(rt);
        l=read();r=read();
        int x=find(rt,l),y=find(rt,r+2);
//      printf("%d %d\n",x,y);
        splay(x,rt);splay(y,ch[x][1]);
        rev[ch[y][0]]^=1;
//      printf("over\n");
    }
    dfs(rt);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值