文艺平衡树 lg3391(splay维护区间入门)

splay是支持区间操作的,先做这道题入个门

大多数操作都和普通splay一样,就不多解释了,只解释一下不大一样的操作

#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
inline int read(){
    int w=0,f=1;
    char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){
        if(ch==‘-‘) f=-1;
        ch=getchar();
    }
    while(ch>=‘0‘&&ch<=‘9‘){
        w=(w<<3)+(w<<1)+ch-48;
        ch=getchar();
    }
    return w*f;
}
int n,m,tot,cnt,root;
struct node{
    int ch[2],sum,cnt,val,f,rev;//比普通平衡树多一个lazy tag
}st[1000010];
inline void push_up(int p){
    st[p].sum=st[st[p].ch[0]].sum+st[st[p].ch[1]].sum+st[p].cnt;
}
inline bool identify(int p){
    return st[st[p].f].ch[1]==p;
}
inline void connect(int x,int fa,int son){
    st[x].f=fa;st[fa].ch[son]=x;return;
}
inline void rotate(int x){
    int y=st[x].f;int z=st[y].f;
    int yson=identify(x);int zson=identify(y);
    int b=st[x].ch[yson^1];
    connect(b,y,yson);connect(y,x,(yson^1));connect(x,z,zson);
    push_up(y);push_up(x);return;
}
inline void splay(int x,int goal){
    while(st[x].f!=goal){
        int y=st[x].f;int z=st[y].f;
        int yson=identify(x);int zson=identify(y);
        if(z!=goal){
            if(yson==zson) rotate(y);
            else rotate(x);
        }
        rotate(x);
    }
    if(!goal) root=x;
    return;
}
inline void insert(int x){
    int now=root;int f=0;
    while(st[now].val!=x&&now){
        f=now;
        now=st[now].ch[x>st[now].val];
    }
    if(now){
        st[now].cnt++;
    }
    else{
        tot++;now=tot;
        if(f){
            st[f].ch[x>st[f].val]=now;
        }
        st[now].ch[0]=st[now].ch[1]=0;
        st[now].cnt=st[now].sum=1;
        st[now].val=x;st[now].f=f;
    }
    splay(now,0);return;
}
inline void push_down(int p){
    int ls=st[p].ch[0];int rs=st[p].ch[1];
    if(st[p].rev){
        swap(st[p].ch[0],st[p].ch[1]);
        st[st[p].ch[0]].rev^=1;
        st[st[p].ch[1]].rev^=1;
        st[p].rev=0;
    }
}
inline void find(int x){
    int now=root;if(!now) return;
    while(st[now].val!=x&&st[now].ch[x>st[now].val]){
        now=st[now].ch[x>st[now].val];
    }
    splay(now,0);return;
}
inline int Next(int x,int f){
    find(x);int now=root;
    if(st[now].val<x&&!x) return now;
    if(st[now].val>x&&x) return now;
    now=st[now].ch[f];
    while(st[now].ch[f^1]) now=st[now].ch[f^1];
    return now;
}
inline int k_th(int x){
    int now=root;
    if(st[now].sum<x) return false;
    while(true){
        push_down(now);//在查找的时候记得下移标记
        int ls=st[now].ch[0];
        if(x>st[ls].sum+st[now].cnt){
            x-=st[ls].sum+st[now].cnt;
            now=st[now].ch[1];
        }
        else if(x<=st[ls].sum){
            now=ls;
        }
        else return now;//这个地方把返回原值改成返回位置
    }
}inline void rev(int l,int r){
    int x=k_th(l-1);int y=k_th(r+1);
    splay(x,0);splay(y,x);
    st[st[y].ch[0]].rev^=1;
}//翻转的操作就是将l-1转到根上,r+1转到根的右儿子,然后l到r这个区间就是根右儿子的左儿子(比较绕,可以画个图想一想
inline void output(int p){
    push_down(p);
    if(st[p].ch[0]) output(st[p].ch[0]);
    if(st[p].val>=1&&st[p].val<=n) printf("%d ",st[p].val);
    if(st[p].ch[1]) output(st[p].ch[1]);
}//输出的时候下推一下标记,输出顺序就是二叉树的顺序
int main(){
    n=read();m=read();int i,j,k;
    insert(INF);insert(-INF);
    for(i=1;i<=n;i++){
        insert(i);
    }
    while(m--){
        int x,y;x=read();y=read();
        rev(x+1,y+1);
    }
    output(root);
    return 0;
}

原文地址:https://www.cnblogs.com/wenci/p/10122634.html

时间: 2024-11-03 01:48:50

文艺平衡树 lg3391(splay维护区间入门)的相关文章

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

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,

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

洛谷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

洛谷P3391 【模板】文艺平衡树(Splay)(FHQ Treap)

题目背景 这是一道经典的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

【模板】文艺平衡树(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

文艺平衡树(splay)

文艺平衡树(luogu) Description 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列. 其中需要提供以下操作:翻转一个区间,例如原有序序列是 5\ 4\ 3\ 2\ 15 4 3 2 1,翻转区间是 [2,4][2,4] 的话,结果是 5\ 2\ 3\ 4\ 15 2 3 4 1. 输入格式 第一行两个正整数 n,mn,m,表示序列长度与操作个数.序列中第 ii 项初始为 ii.接下来 mm 行,每行两个正整数 l,rl,r,表示翻转的区间. 输出格式 输出一行

文艺平衡树(splay模板)

题干:splay模板,要求维护区间反转. splay是一种码量小于treap,但支持排名,前驱后继等treap可求的东西,也支持区间反转的平衡树. 但是有两个坏处: 1.splay常数远远大于treap以及stl中的set. 2.没有可持久化splay,但有可持久化treap. 下面是代码: 1.pushup以及pushdown pushup用于维护某点所在子树大小. void pushup(int u) { tr[u].siz = tr[tr[u].ch[0]].siz + tr[tr[u].

【BZOJ】3223: Tyvj 1729 文艺平衡树(splay)

http://www.lydsy.com/JudgeOnline/problem.php?id=3223 默默的.. #include <cstdio> #include <cstring> #include <cmath> #include <string> #include <iostream> #include <algorithm> #include <queue> #include <set> #in

洛谷:P3384 【模板】文艺平衡树(Splay)

原题地址:https://www.luogu.org/problemnew/show/P3391 题目简述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 思路 首先明白Splay比起线段树能多干什么: 可以在一个有序序列中任意数后面动态插入一串数(不能比a后面一个数还大) 可以删除一段区间 可能描述不是很清楚,具体看这里面给的论文链接:信息学竞赛相关优秀文章