[洛谷 P3377]【模板】左偏树(可并堆)

解析

论文:左偏树的特点及其应用

0. 吐槽
怀疑这题是并查集,,,找根有点烦
以前一直觉得很厉害的样纸,其实还是可以接受的(别和我说证明,不听)
PS:已退役,过来划水
1. 笔记
功能:在 O ( log ⁡ 2 n ) O( \log_{2}n) O(log2n)内进行堆的合并
核心:key(堆的性质), dis(左偏性质)
关键操作:合并;删除
左偏性质:保证 d i s ( l c h ) ≥ d i s ( r c h ) dis(lch) \geq dis(rch) dis(lch)dis(rch),其中 d i s ( p ) = d i s ( r c h ) + 1 dis(p) = dis(rch) + 1 dis(p)=dis(rch)+1
… \dots
2. 关于本题
左偏树相关的只有合并操作
关于找根:并查集维护(带路径压缩);将删除点指向合并后的根节点

代码

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>

#define IL inline

using namespace std; 

IL int read()
{
	int sum = 0;
	bool f = 0;
	char c = getchar();
	for(; '0' > c || c > '9'; c = getchar())
	if(c == '-') f = 1;
	for(; '0' <= c && c <= '9'; c = getchar())
		sum = sum * 10 + (c - '0');
	return f ? -sum : sum;
}

const int N(100005);
int n, m;

int ch[N][2], val[N], dis[N], fa[N];

IL int Find(int x)
{
	int p = x;
	for(; fa[p] != p; p = fa[p]);
	for(int tmp; x != p; )
	{
		tmp = fa[x];
		fa[x] = p;
		x = tmp;
	}
	return p;
}

IL int Merge(int x, int y)
{
	if(!x) return y;
	if(!y) return x;
	if(val[x] > val[y]) swap(x, y);
	ch[x][1] = Merge(ch[x][1], y);
	fa[ch[x][1]] = x;
	if(dis[ch[x][0]] < dis[ch[x][1]]) swap(ch[x][0], ch[x][1]);
	dis[x] = dis[ch[x][1]] + 1;
	return x;
}

int main()
{
	n = read(); m = read(); 
	for(int i = 1; i <= n; ++i)
	{
		val[i] = read(); fa[i] = i;
	}
	val[0] = -1;
	
	for(int op, x, y; m; --m)
	{
		op = read(); x = read();
		if(op == 1)
		{
			y = read();
			if(val[x] == -1 || val[y] == -1) continue;
			x = Find(x); y = Find(y); 
			if(x == y) continue;
			Merge(x, y);
		}else
		if(op == 2)
		{
			if(val[x] == -1) { printf("-1\n"); continue; }
			x = Find(x);
			printf("%d\n", val[x]);
			fa[ch[x][0]] = ch[x][0];
			fa[ch[x][1]] = ch[x][1];
			val[x] = -1;
			fa[x] = Merge(ch[x][0], ch[x][1]);
		}
	}
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
洛谷P1168题目是关于中位数线段树解法的问题。中位数线段树解法可以通过维护两个来实现。一个是大根,一个是小根。每次插入元素时,根据一定的规则来维护这两个,使得大根的个数在一定情况下比小根多1或者相等。大根的最后一个元素即为中位数。具体的规则如下: 1. 如果大根和小根的个数相等,下一次插入的元素一定插入到大根。此时判断小根顶是否大于当前元素x,如果是,则将小根顶元素插入到大根,然后将x压入小根;否则直接将x压入大根。 2. 如果大根和小根的个数不相等,按照类似的规则进行操作。 通过以上规则,可以实现在每次插入元素时,维护两个的平衡,并且保证大根的最后一个元素即为中位数。 这种解法的时间复杂度为O(logN),其中N为序列的长度。 #### 引用[.reference_title] - *1* *2* [中位数(洛谷p1168)(/树状数组+二分/线段树+二分)](https://blog.csdn.net/qq_45604735/article/details/114382762)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [洛谷 P1168 中位数(权值线段树,离散化)](https://blog.csdn.net/qq_38232157/article/details/127594230)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值