bzoj3223 Tyvj1729 文艺平衡树 splay

本文介绍了一种基于Splay树实现区间翻转的数据结构,适用于动态维护有序数列并进行区间翻转操作。通过旋转操作调整树结构,实现区间翻转功能。

Description


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

N,M<=100000

Solution


裸的splay区间翻转,但是我不会╮(╯▽╰)╭
为了能区间操作我们需要按照下标为关键字建一棵splay,区间翻转(l,r)就把l-1旋到根,r+1旋到根的右儿子,这样r+1的左儿子就是我们要操作的区间了,像线段树一样打lazy即可
下传翻转的操作就是交换左右子树,注意深度较浅的节点先被下传,同理深度较深的节点先被上传更新
感觉这样splay和rotate操作简短一些,好记

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
const int N=400005;
int son[N][2],fa[N],size[N],lazy[N],val[N];
int root=0,cnt=0;
int n,m;
int read() {
    int x=0,v=1; char ch=getchar();
    for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
    for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
    return x*v;
}
void push_up(int x) {size[x]=size[son[x][0]]+size[son[x][1]]+1;}
void push_down(int x) {
    if (!lazy[x]) return ;
    lazy[son[x][0]]^=1; lazy[son[x][1]]^=1;
    std:: swap(son[x][0],son[x][1]);
    lazy[x]=0;
}
void rotate(int x) {
    int y=fa[x]; int z=fa[y];
    int k=son[y][1]==x;
    son[z][son[z][1]==y]=x;
    fa[x]=z;
    son[y][k]=son[x][k^1];
    fa[son[x][k^1]]=y;
    son[x][k^1]=y;
    fa[y]=x;
    push_up(y); push_up(x);
}
void splay(int x,int goal) {
    while (fa[x]!=goal) {
        int y=fa[x]; int z=fa[y];
        if (z!=goal) {
            if ((son[z][1]==y)^(son[y][1]==x)) rotate(x);
            else rotate(y);
        }
        rotate(x);
    }
    if (!goal) root=x;
}
void insert(int v) {
    int x=root,father=0;
    while (x) father=x,x=son[x][v>val[x]];
    x=++cnt; fa[x]=father; val[x]=v; size[x]=1;
    if (father) son[father][v>val[father]]=x;
    splay(x,0);
}
int query(int k) {
    int x=root;
    while (233) {
        push_down(x);
        if (size[son[x][0]]>=k) x=son[x][0];
        else if (size[son[x][0]]+1==k) return x;
        else k-=size[son[x][0]]+1,x=son[x][1];
    }
}
void output(int x) {
    push_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 reverse(int l,int r) {
    l=query(l);
    r=query(r+2);
    splay(l,0); splay(r,l);
    lazy[son[son[root][1]][0]]^=1;
}
int main(void) {
    n=read(),m=read();
    rep(i,1,n+2) {
        insert(i);
    }
    while (m--) {
        int l=read(),r=read();
        reverse(l,r);
    }
    output(root);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值