文艺平衡树笔记——fhq

文艺平衡树笔记—— fhq Treap

P3391 【模板】文艺平衡树#

题意#

  • 给你一个数列 1n ,要求支持一种操作:
    • 给定一个区间 [l,r] ,翻转这个区间。
    • 比如, 1 2 3 4 5 ,翻转 [1,3] 之后,得到 3 2 1 4 5
  • 最后输出翻转后的序列。

做法#

  • 我们继续用 fhq Treap 做。

    • 啊啊啊这fhq怎么搞区间操作啊
  • 为啥不行 (¨)

  • 我们让 fhq Treap线段树学习。

    • 我们给 fhq Treap 加一个线段树的 lazy_tag ,表示这棵子树要不要被翻转。
    • 然后经典的标记下放。
    • 下放时要异或,不是加,不是减。
  • 我们考虑分裂操作:

  • 我们考虑合并操作

    • 在合并时加上标记下放即可
  • 我们考虑翻转操作

    • 我们先按大小 l1 把原树分裂成 xz ,再按 rl+1x 分裂成 xy
    • 为啥是这俩数捏?
    • 我们对 [l,r] 操作,那么在 l 前面还有 l1 个数,而我们要操作的数有 rl+1 个。
    • 就这样了。
  • 我们考虑输出

    • 就是中序遍历啦

Code#

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int n,m;
struct node{//fhq节点定义
	int l,r,key,size,val;
	bool tag;
}fhq[maxn];
int cnt=0,root=0;
int newnode(int val){//新建节点
	fhq[++cnt].val=val;
	fhq[cnt].key=rand();
	fhq[cnt].size=1;
	fhq[cnt].l=fhq[cnt].r=fhq[cnt].tag=0;
	return cnt;
}
void update(int x){//更新大小
	fhq[x].size=fhq[fhq[x].l].size+fhq[fhq[x].r].size+1;
}
void lazy_tag(int x){//标记下放
	if(!fhq[x].tag)return;
	swap(fhq[x].l,fhq[x].r);
	fhq[fhq[x].l].tag^=1;
	fhq[fhq[x].r].tag^=1;
	fhq[x].tag=0;
}
void split(int now,int size,int &x,int &y){//大小分裂
	if(!now)x=y=0;
	else{
		lazy_tag(now);
		if(fhq[fhq[now].l].size<size){
			x=now;
			split(fhq[now].r,size-fhq[fhq[now].l].size-1,fhq[now].r,y);
		}
		else{
			y=now;
			split(fhq[now].l,size,x,fhq[now].l);
		}
		update(now);
	}
}
int merge(int x,int y){//合并
	if(!x||!y)return x|y;
	if(fhq[x].key<fhq[y].key){
		lazy_tag(x);
		fhq[x].r=merge(fhq[x].r,y);
		update(x);
		return x;
	}
	else{
		lazy_tag(y);
		fhq[y].l=merge(x,fhq[y].l);
		update(y);
		return y;
	}
}
void rev(int l,int r){//翻转
	int x,y,z;
	split(root,l-1,x,y);
	split(y,r-l+1,y,z);
	fhq[y].tag=1;
	root=merge(merge(x,y),z);
}
void print(int now){//输出
	if(!now)return;
	lazy_tag(now);
	print(fhq[now].l);
	cout<<fhq[now].val<<' ';
	print(fhq[now].r);
}
int main(){//显然,主函数
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)root=merge(root,newnode(i));
	for(int i=1,a,b;i<=m;i++){
		scanf("%d%d",&a,&b);
		rev(a,b);
	}
	print(root);
	return 0;
}

注意逝项#

  1. 输出过程中也要进行标记下放操作
  2. 标记下放很多,容易漏掉
  3. 大小分裂容易写错

The End

posted @   洛谷Augury  阅读(150)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
more_horiz
keyboard_arrow_up light_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示