bzoj3223[Tyvj 1729] 文艺平衡树(splay模板题:区间翻转)
来源:互联网 发布:java开源文件管理系统 编辑:程序博客网 时间:2024/06/05 05:13
Description
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1
Input
第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2……n-1,n) m表示翻转操作次数
接下来m行每行两个数[l,r] 数据保证 1<=l<=r<=n
Output
输出一行n个数字,表示原始序列经过m次变换后的结果
Sample Input
5 3
1 3
1 3
1 4
1 3
1 3
1 4
Sample Output
4 3 2 1 5
HINT
N,M<=100000
Source
平衡树
分析:
splay的经典操作,没有冗杂的insert和delet
我们只需要记录一个翻转标记
首先我们需要按照下标的大小建立一棵splay
假设我们需要翻转(x,y)区间,我们只需要把x-1换到根上,y+1换到根的右儿子上
这样(x,y)内的所有数就集中在了root—>rightchiold—>leftchild
我们只要打上一个翻转标记即可
翻转标记的效果就是翻转左右儿子
大体思路已经口hu完了
但是我们还有一些细节需要处理:
First.
我们翻转的区间可能是(x,n)或者(1,x),这样我们就找不到区间的前驱或后继
所以我们需要在两头分别添加一个无用节点,v分别是-INF和INF
所以就有了这几句:
a[0]=-INF; a[n+1]=INF;for (int i=1;i<=n;i++) a[i]=i;root=build(0,n+1,0);
我们在构建初始splay的时候,实际上把a[0]代表的值放在了一号结点的位置上
所以如果要查询区间(x,y)
ta的前驱就是结点x,后继是结点y+2
Second.
我们在构建初始的平衡树时,一个一个insert肯定是很愚蠢的
但是如果我们直接构建成一条链,在之后的处理中会浪费很多时间
受到线段树的启发,我们这样建树:
int build(int l,int r,int fa){ if (l>r) return 0; int mid=(l+r)>>1; int now=++top; ch[now][0]=build(l,mid-1,now); ch[now][1]=build(mid+1,r,now); pre[now]=fa; rev[now]=0; v[now]=a[mid]; update(now); return now;}
tip
在splay之前,我们需要先下传标记
于是我直接写了一个down函数:
void down(int bh){ if (pre[bh]) down(pre[bh]); push(bh);}
时刻push:splay,find,print
线段树作为一种基础数据结构,再很多高级数据结构中都会涉及到ta的思想
//这里写代码片#include<cstdio>#include<iostream>#include<iostream>using namespace std;const int INF=1e9+7;const int N=100010;int v[N],ch[N][2],size[N],pre[N],a[N];int n,root,top=0,m;bool rev[N];int get(int bh){ return ch[pre[bh]][0]==bh? 0:1;}void update(int bh){ if (!bh) return; size[bh]=1; if (ch[bh][0]) size[bh]+=size[ch[bh][0]]; if (ch[bh][1]) size[bh]+=size[ch[bh][1]];}void push(int bh){ if (!bh) return; if (rev[bh]) { if (ch[bh][0]) rev[ch[bh][0]]^=1; if (ch[bh][1]) rev[ch[bh][1]]^=1; swap(ch[bh][0],ch[bh][1]); rev[bh]^=1; }}void rotate(int bh){ int fa=pre[bh]; int grand=pre[fa]; int wh=get(bh); ch[fa][wh]=ch[bh][wh^1]; pre[ch[fa][wh]]=fa; ch[bh][wh^1]=fa; pre[fa]=bh; pre[bh]=grand; if (grand) ch[grand][ch[grand][0]==fa? 0:1]=bh; update(fa); update(bh);}void down(int bh){ if (pre[bh]) down(pre[bh]); push(bh);}int splay(int bh,int mb){ down(bh); // for (int fa;(fa=pre[bh])!=mb;rotate(bh)) if (pre[fa]!=mb) rotate(get(bh)==get(fa)? fa:bh); if (mb==0) root=bh;}int find(int x){ int now=root; while (1) { push(now); // if (size[ch[now][0]]>=x) now=ch[now][0]; else { int tmp=(ch[now][0]? size[ch[now][0]]:0); tmp++; if (tmp>=x) return now; x-=tmp; now=ch[now][1]; } }}void print(int now){ push(now); // if (ch[now][0]) print(ch[now][0]); if (v[now]!=INF&&v[now]!=-INF) printf("%d ",v[now]); if (ch[now][1]) print(ch[now][1]);}int build(int l,int r,int fa){ if (l>r) return 0; int mid=(l+r)>>1; int now=++top; ch[now][0]=build(l,mid-1,now); ch[now][1]=build(mid+1,r,now); pre[now]=fa; rev[now]=0; v[now]=a[mid]; update(now); return now;}int main(){ scanf("%d%d",&n,&m); a[0]=-INF; a[n+1]=INF; for (int i=1;i<=n;i++) a[i]=i; root=build(0,n+1,0); for (int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); int xx=find(x); int yy=find(y+2); splay(xx,0); splay(yy,xx); rev[ch[ch[root][1]][0]]^=1; } print(root); return 0;}
阅读全文
0 0
- bzoj3223[Tyvj 1729] 文艺平衡树(splay模板题:区间翻转)
- bzoj3223 Tyvj 1729 文艺平衡树(Splay Tree+区间翻转)
- bzoj 3223: Tyvj 1729 文艺平衡树(splay 模板题 区间翻转)
- bzoj3223: Tyvj 1729 文艺平衡树 splay裸区间旋转
- 【bzoj3223】Tyvj 1729 文艺平衡树 Splay
- 【BZOJ3223】Tyvj 1729 文艺平衡树【Splay】
- bzoj3223 Tyvj 1729 文艺平衡树 (splay)
- (带讲解)bzoj3223: Tyvj 1729 文艺平衡树 平衡树上的区间翻转标记
- BZOJ3223[Tyvj 1729 文艺平衡树]题解--splay
- splay区间翻转bzoj 3223(tyvj 1729)文艺平衡树题解
- splay区间翻转(bzoj 3223: Tyvj 1729 文艺平衡树)
- 【BZOJ3223】文艺平衡树,Splay反转区间
- splay 新模板 【bzoj3223】 文艺平衡树
- BZOJ3223&3224 文艺&普通平衡树 Splay模板(数组)
- splay处理区间翻转例题【BZOJ 3223】 Tyvj 1729 文艺平衡树
- [Bzoj3223]Tyvj 1729 文艺平衡树
- [BZOJ3223]Tyvj 1729 文艺平衡树
- [BZOJ3223] Tyvj 1729 文艺平衡树
- 【CSS】基于视口单位vw vh vmin vmax 以及 rem和ch
- 如何在Android studio中更新sdk版本和build-tools版本
- Ubuntu16.04安装LSD-SLAM
- Hadoop、Hive等介绍
- Servlet和Ajax传递JSON
- bzoj3223[Tyvj 1729] 文艺平衡树(splay模板题:区间翻转)
- 解决Incorrect integer value: for column id; at row 1
- Noip2017那两天的经历
- 不同架构的字节顺序释疑
- android 输入法软件盘弹出遮挡原界面
- svn 中的switch的使用
- CentOS & Ubuntu 查看网口信息脚本
- 文章标题
- algo_ADMM(alternating direction multiplier method)