文艺平衡树(Splay)

题意

给出一个序列,m次操作翻转区间[l,r],如1,5,4,2变成2,4,5,1

求最后的序列

n,m100000

题解

普通的splay维护的权值,如果维护序列的话就维护序列下标即可,即splay的中序遍历就是原序列。

提取一段区间[l,r]就把l-1旋到根,r+1旋到根的右儿子,那么这段区间就在r+1的左二子那部分。

提取出来后一段区间的结构都是一颗树,那么翻转区间就在树的根打上标记代表他的左右儿子需要交换。

标记下传在find中即可,因为所有操作都要经过这一步。

 

#include<bits/stdc++.h>
using namespace std;

const int maxn=100005;
const int oo=100000000;
int n,m,root,num,a[maxn];
struct point{
    int size,fa,v,tag,s[2];
}tr[maxn];

template<class T>inline void read(T &x){
    x=0;char ch=getchar();
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
}

int build(int l,int r,int f){
    if(l>r) return 0;
    int now=++num,mid=(l+r)>>1;
    tr[now].fa=f;
    tr[now].v=a[mid];
    tr[now].size++;
    tr[now].s[0]=build(l,mid-1,now);
    tr[now].s[1]=build(mid+1,r,now);
    tr[now].size+=tr[tr[now].s[1]].size+tr[tr[now].s[0]].size;
    return now;
}


void pushdown(int x){
    if(!tr[x].tag) return ;
    tr[tr[x].s[0]].tag^=1;
    tr[tr[x].s[1]].tag^=1;
    swap(tr[x].s[0],tr[x].s[1]);
    tr[x].tag=0;
}

int find(int x){
    int now=root;
    while(1){
        pushdown(now);
        if(x<=tr[tr[now].s[0]].size) {now=tr[now].s[0]; continue;}
        x=x-(tr[tr[now].s[0]].size+1);
        if(!x) return now;
        now=tr[now].s[1];
    }
}

int indenti(int x){ return tr[tr[x].fa].s[1]==x;}

void connect(int x,int y,int d){
    tr[x].fa=y;
    tr[y].s[d]=x;
}

void update(int x){
    int ls=tr[x].s[0],rs=tr[x].s[1];
    tr[x].size=tr[ls].size+tr[rs].size+1;
}

void rotate(int x){
    int f=tr[x].fa,ff=tr[f].fa;
    int d1=indenti(x);
    int d2=indenti(f);
    int cs=tr[x].s[d1^1];
    connect(x,ff,d2);
    connect(f,x,d1^1);
    connect(cs,f,d1);
    update(f);
    update(x);
}

void splay(int x,int go){
    if(go==root) root=x;
    go=tr[go].fa;
    while(tr[x].fa!=go){
        int f=tr[x].fa;
        if(tr[f].fa==go) rotate(x);
        else if(indenti(x)==indenti(f)) {rotate(f);rotate(x);}
        else {rotate(x);rotate(x);}
    }
}

void cx(int x,int y){
    int l=find(x-1),r=find(y+1);//找区间[x,y]的前驱和后继
    splay(l,root);
    splay(r,tr[l].s[1]);
    int pos=tr[root].s[1];
    pos=tr[pos].s[0];//找到[x,y]整颗子树的根
    tr[pos].tag^=1; 
}

void nice(int x){
    pushdown(x);
    if(tr[x].s[0]) nice(tr[x].s[0]);
    if(tr[x].v!=oo&&tr[x].v!=-oo) printf("%d ",tr[x].v);
    if(tr[x].s[1]) nice(tr[x].s[1]);
}

int main(){
    read(n);read(m);
    a[1]=-oo;a[n+2]=oo;
    for(int i=1;i<=n;i++) a[i+1]=i;
    root=build(1,n+2,0);
    for(int i=1;i<=m;i++){
        int x,y;read(x);read(y);
        cx(x+1,y+1);//加入了-oo 
    }
    nice(root);
}
View Code

 

转载于:https://www.cnblogs.com/sto324/p/11297573.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本方法。编译原理不仅是计算机科学理论的重要组成部分,也是实现高效、可靠的计算机程序设计的关键。本文将对编译原理的基本概念、发展历程、主要内容和实际应用进行详细介绍编译原理是计算机专业的一门核心课程,旨在介绍编译程序构造的一般原理和基本

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值