真的是个神题,蒟蒻表示无力吐槽。刚开始以为是一个板子题,看着题解打了一遍,大概也理解了他是怎么实现的,然后我就去做别的题了,然后就在Three_D大佬的询问下蒙*了。最后还是问的nc哥,并思考了一个中午才搞明白。最主要的一点是,旋转不会改变树的中序遍历。

【建树操作】

  对于一棵BST,区间[l,r],如果把l-1 splay到根,把r+1 splay到根的右子树,那么[l,r]即为根的右子树的左子树,如果不是BST,这个性质同样适用。然后因为旋转可能会涉及到1,n,所以要建立1,n+2两个哨兵节点;因为平衡树维护的是一个序列,所以一开始树的中序遍历应该是原序列:

 rt=build_tree(,,n+);
int build_tree(int fa,int l,int r)
{
if(l>r) return ;
int mid=(l+r)>>,
now=++sz;
key[now]=data[mid];f[now]=fa;tag[now]=;
ch[now][]=build_tree(now,l,mid-);
ch[now][]=build_tree(now,mid+,r);
pushup(now);
return now;
}

【splay】

  rotate不改变树的中序遍历,原rotate函数不变。因为要将r+2 splay到根的右节点而不是根,所以要多传一个参:

 void splay(int x,int goal)
{
for(int fa;(fa=f[x])!=goal;rotate(x))
if(f[fa]!=goal)
rotate(get(fa)==get(x)?fa:x);
if(!goal)rt=x;
}

【翻转区间】*

  对于区间[l,r],将l splay到根,r+2 splay到根的右儿子,那么r+2的左子树就是[l+1,r+1].如果将r+2的左儿子的左右子树翻转,并递归地翻转下去,那么[l+1,r+1]的中序遍历就会翻转。但是这样的时间复杂度太高,所以延续线段树中懒标记的操作。

 void turn(int l,int r)
{
l=rnk(l);
r=rnk(r+);
splay(l,);
splay(r,l);
pushdown(rt);
tag[ch[ch[rt][]][]]^=;
}

  然后说说把我弄懵逼的东西,对于序列 [12345],平衡树如图:

  绿色的数字为key值,一定要注意区分节点的排名和这个节点的值,在建树时,key[now]=data[mid];当前节点的key存储的是序列的值,而图中黑色的数字是节点的排名,可能有点难以理解,那举个例子:

  对于[12345],如果要翻转区间[2,3],那么在平衡树中找到排名为2的数(l=rnk(l)),即2,将他旋转到根,找到排名为5的数(r=rnk(r+2)),即5,将他旋转到根的右儿子,则5的左子树为[34],key值就是所要翻转的区间[23],打上标记,翻转完成。

Ps.除区间翻转外,还可以进行区间删除,区间加上x等操作。

标记下传】

  每到一个节点就要下传懒标记:

 void pushdown(int x)
{
if(x && tag[x])
{
tag[ch[x][]]=tag[ch[x][]]^;
tag[ch[x][]]=tag[ch[x][]]^;
swap(ch[x][],ch[x][]);
tag[x]=;
}
}

【输出结果】

  中序遍历整棵树即可:

 void write(int now)
{
pushdown(now);
if(ch[now][])write(ch[now][]);
if(key[now]!=INF && key[now]!=-INF)cout<<key[now]<<" ";
if(ch[now][]) write(ch[now][]);
}

【完整代码

 #include<iostream>
#include<cstdio>
#include<cmath>
#define INF 0x7fffffff
using namespace std;
int n,m,data[];
int ch[][],size[],cnt[],f[],key[],tag[],sz,rt; int get(int x){return ch[f[x]][]==x;}
void pushup(int x)
{
size[x]=size[ch[x][]]+size[ch[x][]]+;
}
void pushdown(int x)
{
if(x && tag[x])
{
tag[ch[x][]]=tag[ch[x][]]^;
tag[ch[x][]]=tag[ch[x][]]^;
swap(ch[x][],ch[x][]);
tag[x]=;
}
}
int build_tree(int fa,int l,int r)
{
if(l>r) return ;
int mid=(l+r)>>,
now=++sz;
key[now]=data[mid];f[now]=fa;tag[now]=;
ch[now][]=build_tree(now,l,mid-);
ch[now][]=build_tree(now,mid+,r);
pushup(now);
return now;
}
void rotate(int x)
{
int old=f[x],oldf=f[old],which=get(x);
pushdown(oldf),pushdown(old),pushdown(x);
ch[old][which]=ch[x][which^];f[ch[old][which]]=old;
ch[x][which^]=old;f[old]=x;
f[x]=oldf;
if(oldf) ch[oldf][ch[oldf][]==old]=x;
pushup(old),pushup(x);
}
void splay(int x,int goal)
{
for(int fa;(fa=f[x])!=goal;rotate(x))
if(f[fa]!=goal)
rotate(get(fa)==get(x)?fa:x);
if(!goal)rt=x;
}
int rnk(int x)
{
int now=rt;
while()
{
pushdown(now);
if(x<=size[ch[now][]])now=ch[now][];
else
{
x-=size[ch[now][]]+;
if(!x)return now;
now=ch[now][];
}
}
}
void turn(int l,int r)
{
l=rnk(l);
r=rnk(r+);
splay(l,);
splay(r,l);
pushdown(rt);
tag[ch[ch[rt][]][]]^=;
}
void write(int now)
{
pushdown(now);
if(ch[now][])write(ch[now][]);
if(key[now]!=INF && key[now]!=-INF)cout<<key[now]<<" ";
if(ch[now][]) write(ch[now][]);
}
signed main()
{
cin>>n>>m;
for(int i=;i<=n;i++)data[i+]=i;
data[]=-INF,data[n+]=INF;
rt=build_tree(,,n+);
int x,y;
for(int i=;i<=m;i++)
{
cin>>x>>y;
turn(x,y);
}
write(rt);
return ;
}

文艺平衡树-splay的区间操作的更多相关文章

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

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

  2. Splay 的区间操作

    学完Splay的查找作用,发现和普通的二叉查找树没什么区别,只是用了splay操作节省了时间开支. 而Splay序列之王的称号可不是白给的. Splay真正强大的地方是他的区间操作. 怎么实现呢? 我 ...

  3. 【阶梯报告】洛谷P3391【模板】文艺平衡树 splay

    [阶梯报告]洛谷P3391[模板]文艺平衡树 splay 题目链接在这里[链接](https://www.luogu.org/problemnew/show/P3391)最近在学习splay,终于做对 ...

  4. luoguP3391[模板]文艺平衡树(Splay) 题解

    链接一下题目:luoguP3391[模板]文艺平衡树(Splay) 平衡树解析 这里的Splay维护的显然不再是权值排序 现在按照的是序列中的编号排序(不过在这道题目里面就是权值诶...) 那么,继续 ...

  5. BZOJ3223: Tyvj 1729 文艺平衡树 [splay]

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

  6. Tyvj P1729 文艺平衡树 Splay

    题目: http://tyvj.cn/p/1729 P1729 文艺平衡树 时间: 1000ms / 空间: 131072KiB / Java类名: Main 背景 此为平衡树系列第二道:文艺平衡树 ...

  7. BZOJ 3223: Tyvj 1729 文艺平衡树(splay)

    速度居然进前十了...第八... splay, 区间翻转,用一个类似线段树的lazy标记表示是否翻转 ------------------------------------------------- ...

  8. bzoj3223Tyvj 1729 文艺平衡树 splay

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

  9. bzoj 3223: Tyvj 1729 文艺平衡树 (splay)

    链接: https://www.lydsy.com/JudgeOnline/problem.php?id=3223 题面: 3223: Tyvj 1729 文艺平衡树 Time Limit: 10 S ...

随机推荐

  1. Html.RenderPartial使用三个参数

    Html.RenderPartial("usercontrolurl", model, ViewDataDictionary) 当使用三个参数时可以这样使用: var data = ...

  2. redis Database Eviction Policies Redis on Flash

    Database Eviction Policies - Redis Enterprise Software | Redis Labs https://redislabs.com/redis-ente ...

  3. Vijos 1144 小胖守皇宫 【树形DP】

    小胖守皇宫 描述 huyichen世子事件后,xuzhenyi成了皇上特聘的御前一品侍卫. 皇宫以午门为起点,直到后宫嫔妃们的寝宫,呈一棵树的形状:某些宫殿间可以互相望见.大内保卫森严,三步一岗,五步 ...

  4. go17---并发

    yjf512 · 2015-02-21 11:09:07 · 1076 次点击 · 预计阅读时间 2 分钟 · 大约1分钟之前 开始浏览     这是一个创建于 2015-02-21 11:09:07 ...

  5. 【Silverlight】Bing Maps学习系列(七):使用Bing Maps的图片系统(Tile System)

    [Silverlight]Bing Maps学习系列(七):使用Bing Maps的图片系统(Tile System) 目前包括微软必应地图在内的几乎所有在线电子地图(如:Google Maps等)都 ...

  6. [Codeforces 466C] Number of Ways

    [题目链接] https://codeforces.com/contest/466/problem/C [算法] 维护序列前缀和 , 枚举中间一段即可 , 详见代码 时间复杂度 : O(N) [代码] ...

  7. Windows路径

    绝对路径 是从盘符开始的路径,形如 C:\windows\system32\cmd.exe 相对路径 是从当前目录开始的路径,假如当前目录为C:\windows 要描述上述路径,只需输入 system ...

  8. E20170606-hm

    pipeline   n. 管道; 输油管道; 渠道,传递途径; dump   vt. 倾倒; 倾销; 丢下,卸下; 摆脱,扔弃;   n. 垃圾场; 仓库; 无秩序地累积;

  9. poj 2154 Color【polya定理+欧拉函数】

    根据polya定理,答案应该是 \[ \frac{1}{n}\sum_{i=1}^{n}n^{gcd(i,n)} \] 但是这个显然不能直接求,因为n是1e9级别的,所以推一波式子: \[ \frac ...

  10. bzoj 1643: [Usaco2007 Oct]Bessie's Secret Pasture 贝茜的秘密草坪【枚举】

    4维枚举平方小于10000的数,相加等于n则ans++ #include<iostream> #include<cstdio> using namespace std; con ...