传送门:>Here<

解法分析

  用splay来维护这个序列。

  一直没有搞明白的是,这里的splay的节点究竟维护的是什么?是权值吗?肯定不是,因为区间是会翻转的,如果维护权值的话很快平衡树就不再满足性质。

  然而从头到尾,唯一始终统一的就是位置——始终是1~n. 因此考虑用节点来维护位置。

  这样在维护splay的时候,翻转一段区间就相当于修改了这一段区间的位置,使原来小的现在大了,原来大的现在小了。放在树上形象的看,就是原来作为父节点的左儿子的统统称为了右儿子。反之亦然。因此只要找出连续的那一段区间,并且翻转左右子树即可。注意为了减少操作次数,可以打懒标记。

  如何找出连续的那一段目标区间?由于要翻转的是区间$[l, r]$,我们可以找到位置(注意,这里的位置也就是平衡树维护的权值的排名了,因此位置i也就是排名第i的)l-1和r+1的点,分别旋转到根节点和根节点的右子树上。这样,根节点的右子节点的左子树就是这段区间了。(想一想,为什么)。特殊的,当边界到达1或n时会溢出,因此我们加入哨兵节点-1和n+1。这样位置i就是排名i+1了。

  值得注意的是何时下传懒标记——根据懒标记的优良传统,不用就不翻转。那唯一要用的时候就是询问位置的时候了,因此只要find的时候下传就可以了。另外翻转两次相当于不翻转,所以用xor1会很方便。

  

/*By QiXingzhi*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#define r read()
#define Max(a,b) (((a)>(b)) ? (a) : (b))
#define Min(a,b) (((a)<(b)) ? (a) : (b))
using namespace std;
typedef long long ll;
const int MAXN = ;
const int INF = ;
inline int read(){
int x = ; int w = ; register int c = getchar();
while(c ^ '-' && (c < '' || c > '')) c = getchar();
if(c == '-') w = -, c = getchar();
while(c >= '' && c <= '') x = (x << ) +(x << ) + c - '', c = getchar();
return x * w;
}
int n,m,L,R;
struct Splay{
int ch[MAXN][],size[MAXN],val[MAXN],fa[MAXN],tag[MAXN],num_node,root;
inline bool Son(int f, int x){
return ch[f][]==x;
}
inline void Update(int x){
size[x] = size[ch[x][]] + size[ch[x][]] + ;
}
inline void Rotate(int x){
int f = fa[x], gf = fa[f];
bool p = Son(f, x), q = !p;
ch[f][p] = ch[x][q];
fa[ch[x][q]] = f;
ch[x][q] = f;
fa[f] = x;
fa[x] = gf;
if(gf != ){
ch[gf][Son(gf,f)] = x;
}else{
root = x;
}
Update(x), Update(f);
}
inline void splay(int x, int target){
while(fa[x] != target){
int f = fa[x], gf = fa[f];
if(gf == target){
Rotate(x);
return;
}
if(Son(gf,f) == Son(f,x)){
Rotate(f), Rotate(x);
}
else{
Rotate(x), Rotate(x);
}
}
}
inline void Insert(int v){
if(root == ){
++num_node;
root = num_node;
size[num_node] = ;
val[num_node] = v;
return;
}
for(int x = root; x != ; x = ch[x][v >= val[x]]){
bool b = v >= val[x];
if(ch[x][b] == ){
++num_node;
ch[x][b] = num_node;
size[num_node] = ;
val[num_node] = v;
fa[ch[x][b]] = x;
splay(ch[x][b], );
}
}
}
inline void Pushdown(int x){
if(x == ) return;
if(!tag[x]) return;
int tmp = ch[x][];
ch[x][] = ch[x][];
ch[x][] = tmp;
tag[x] = ;
tag[ch[x][]] ^= ;
tag[ch[x][]] ^= ;
}
inline int Find(int _k){
int x = root;
for(; x != ;){
Pushdown(x);
if(size[ch[x][]] + == _k){
return x;
}
if(size[ch[x][]] >= _k){
x = ch[x][];
}
else{
_k -= size[ch[x][]] + ;
x = ch[x][];
}
}
}
inline void Reverse(int L, int R){
if(L >= R) return;
splay(Find(L), );
splay(Find(R), root);
tag[ch[ch[root][]][]] ^= ;
}
inline void DEBUG(){
for(int i = ; i <= n; ++i){
printf("%d-->%d lson:%d rson:%d\n",i,val[i],ch[i][],ch[i][]);
}
}
}qxz;
int main(){
// freopen(".in","r",stdin);
n=r, m=r;
qxz.Insert(-);
qxz.Insert(n+);
for(int i = ; i <= n; ++i){
qxz.Insert(i);
}
// qxz.DEBUG();
for(int i = ; i <= m; ++i){
L=r, R=r;
qxz.Reverse(L,R+);
}
for(int i = ; i <= n; ++i){
printf("%d ", qxz.val[qxz.Find(i+)]);
}
return ;
}

「Splay」区间翻转的更多相关文章

  1. 「NOI2016」区间 解题报告

    「NOI2016」区间 最近思维好僵硬啊... 一上来就觉得先把区间拆成两个端点进行差分,然后扫描位置序列,在每个位置维护答案,用数据结构维护当前位置的区间序列,但是不会维护. 于是想研究性质,想到为 ...

  2. 「SDOI2005」区间

    「SDOI2005」区间 传送门 记录每一个位置作为左端点和右端点的出现次数,然后直接考虑差分即可. 参考代码: #include <cstdio> #define rg register ...

  3. bzoj3223 Tyvj 1729 文艺平衡树(Splay Tree+区间翻转)

    3223: Tyvj 1729 文艺平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2202  Solved: 1226[Submit][Sta ...

  4. BZOJ 3223: Tyvj 1729 文艺平衡树-Splay树(区间翻转)模板题

    3223: Tyvj 1729 文艺平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 6881  Solved: 4213[Submit][Sta ...

  5. 【模板】文艺平衡树(Splay) 区间翻转 BZOJ 3223

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

  6. splay(1区间翻转区间最值与区间修改)

    bzoj1251权限题 题目点这里,你懂得 直接上板子,这个要好好体会 操作是最经典的. #include <algorithm> #include <iostream> #i ...

  7. hdu1890 splay维护区间翻转

    这题的建模有点不太一样,是按结点横坐标赋予键值的 同时每次rotate和splay时都要注意下往上往下更新 /* 先建立好splay tree,将结点按num/输入顺序排序,遍历时每次将当前结点提到根 ...

  8. 「Splay」普通平衡树模板

    口诀: $rotate$:先上再下,最后自己 $splay$:祖父未到旋两次,三点一线旋父亲,三点折线旋自己. $delete$:没有儿子就删光.单个儿子删自己.两个儿子找前驱. 易错点: $rota ...

  9. LOJ#2086. 「NOI2016」区间

    $n \leq 500000$个区间,从中挑出一些,使得至少有一个点被$m$个选中区间包含,且选中区间长度的极差最小. 区间题死脑筋晚期:把区间按左端点排序,然后右端点用个优先队列来弹,然后需要维护下 ...

随机推荐

  1. c++入门之引用

    引用通常被用在函数形参传递的过程中.一般的参数传递的过程:将实参进行拷贝,函数中都是对拷贝的变量进行操作,而不是对原变量进行操作.但很多情况下,我们都希望对原变量进行操作.(比如交换两个变量的数值). ...

  2. Python学习第二篇

    list_num=list(range(1,1000001)) print(min(list_num)) print(max(list_num)) print(sum(list_num)) print ...

  3. Atcoder F - LCS (DP-最长公共子序列,输出字符串)

    F - LCS Time Limit: 2 sec / Memory Limit: 1024 MB Score : 100100 points Problem Statement You are gi ...

  4. Django之时间的设置

    Django之时间的设置 在Django的配置文件 settings.py 中,有两个配置参数是跟时间与时区有关的,分别是 TIME_ZONE 和 USE_TZ. 如果USE_TZ设置为True时,D ...

  5. MySQL 高可用性—keepalived+mysql双主

    MySQL 高可用性—keepalived+mysql双主(有详细步骤和全部配置项解释) - 我的博客 - CSDN博客https://blog.csdn.net/qq_36276335/articl ...

  6. Jenkins deploy war to tomcat over https

    ssl - HTTPS login with Spring Security redirects to HTTP - Stack Overflow https://stackoverflow.com/ ...

  7. git fetch 和git pull 的差别

    1.git fetch 相当于是从远程获取最新到本地,不会自动merge,如下指令: git fetch orgin master //将远程仓库的master分支下载到本地当前branch中 git ...

  8. 极验3.0滑动拼图验证的使用--java

    [ 前言: 在登录其他网站的时候,看到有个滑动拼图的验证觉得挺好玩的,以前做一个图片验证的小demo,现在发现很多网站都开始流行滑动拼图的验证了,今天也想自己动手来弄一个. 废话不多说,开始撸起来! ...

  9. vue cli3 vue.config.js 配置详情

    module.exports = {   // 基本路径   baseUrl: process.env.NODE_ENV === 'production'     ? '/'     : '/',   ...

  10. Zookeeper的作用,在Hadoop及hbase中具体作用

    什么是Zookeeper,Zookeeper的作用是什么,在Hadoop及hbase中具体作用是什么 一.什么是Zookeeper ZooKeeper 顾名思义 动物园管理员,他是拿来管大象(Hado ...