首页 > 其他分享 >题解:P11266 【模板】完全体·堆

题解:P11266 【模板】完全体·堆

时间:2024-12-09 15:56:01浏览次数:4  
标签:ch read 题解 P11266 IO print 模板 左偏

题目链接

解题思路

看了题解区,竟然没有人写可爱的左偏树。

我们需要支持四种操作:

  1. 删除集合中的元素。
  2. 取集合中的最小值。
  3. 合并两个集合。
  4. 修改集合中的元素。

那么我们可以用常数极小的左偏树(可并堆) 来解决这道模板题。

对于左偏树的基础操作,详见左偏树-OI Wiki洛谷 P3377【模板】左偏树/可并堆

在支持删除元素的情况下,我们在进行 push_up 操作时需要查找节点 \(x\) 的父节点,因此无法使用路径压缩来查找左偏树的根节点。如果直接向上查找根节点,会导致 TLE。

为了解决这个问题,我们可以引入一个 root 数组,其中 \(root_x\) 存储集合 \(S_x\) 的根节点下标。在每次执行 merge、erase 和 push_up 操作时,对 root 数组进行相应的更新。

在删除操作中,可以直接将元素 \(x\) 从左偏树中删除,然后重新初始化元素 \(x\),将其作为一个独立的左偏树,再将其合并回原来的左偏树,保证了堆的性质。

此外,对于修改操作,还有另一种更高效的处理方式。由于题目保证 \(z<a_y\),我们可以在修改 \(x\) 的权值后与其父节点进行比较。如果 \(x\) 的父节点的权值大于 \(x\) 的权值,则交换 \(x\) 和其父节点的位置。这样常数极小但是我写挂了

整体时间复杂度为 \(O(m\log{n})\),跑得飞快。

以下是使用朴素修改操作的左偏树 AC 代码的提交记录,仅仅跑了 \(325\) ms,比最优解手写巨大数据结构的大佬慢了 \(19\) ms。

参考代码

#include<bits/stdc++.h>
using namespace std;
namespace IO
{
    char buf[1<<20],*p1,*p2;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
    template<typename T>inline T read(T& x)
    {
        char ch=getchar();bool f=true;x=0;
        while(ch<'0'||ch>'9') f&=(bool)(ch^'-'),ch=getchar();
        while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        return x=f?x:-x;
    }
    char pbuf[1<<20],*pp=pbuf;
    inline void push(const char x){if(pp-pbuf==1<<20) fwrite(pbuf,1,1<<20,stdout),pp=pbuf;*pp++=x;}
    inline void flush(){fwrite(pbuf,1,pp-pbuf,stdout);pp=pbuf;}
#define putchar(x) push(x)
    template<typename T>void print(const T x)
    {
        if(x<0){putchar('-');print(-x);return ;}
        if(x>9) print(x/10);putchar(x%10^48);
    }
    template<typename T,typename... Args>inline void read(T& x,Args&... args){read(x);read(args...);}
    template<typename T>inline void print(const T x,const char ch){print(x);putchar(ch);}
#undef getchar
#undef putchar

#define getchar() (IO::p1==IO::p2&&(IO::p2=(IO::p1=IO::buf)+fread(IO::buf,1,1<<20,stdin),IO::p1==IO::p2)?EOF:*IO::p1++)
#define putchar(x) IO::push(x)
#define flush() IO::flush()
}using IO::read,IO::print;
typedef long long ll;

const int N=1e6+1;
int n,m;

int root[N];
struct ZPS{int ls,rs,dis,fa;ll val;}tree[N];
#define ls(x) tree[x].ls
#define rs(x) tree[x].rs
int merge(int x,int y)
{
	if(!x||!y) return x|y;
	if(tree[x].val>tree[y].val||(tree[x].val==tree[y].val&&x>y)) swap(x,y);
	rs(x)=merge(rs(x),y);
	if(tree[ls(x)].dis<tree[rs(x)].dis) swap(ls(x),rs(x));
	tree[x].dis=tree[rs(x)].dis+1;
	return tree[ls(x)].fa=tree[rs(x)].fa=tree[x].fa=x;
}
void push_up(const int x)
{
	if(!x) return ;
	if(tree[ls(x)].dis<tree[rs(x)].dis) swap(ls(x),rs(x));
	if(tree[x].dis^(tree[ls(x)].dis+1))
		tree[x].dis=tree[ls(x)].dis+1,push_up(tree[x].fa);
}
inline int erase(const int x,const int pos)
{
	int y=merge(ls(x),rs(x));
	if(tree[x].fa^x)
	{
		tree[y].fa=tree[x].fa;
		if(ls(tree[y].fa)==x) ls(tree[y].fa)=y;
		if(rs(tree[y].fa)==x) rs(tree[y].fa)=y;
		push_up(tree[y].fa);
	}else root[pos]=tree[y].fa=y;
	tree[x].fa=y;ls(x)=rs(x)=0;
	return pos;
}
inline ll top(const int pos){return tree[root[pos]].val;}
inline void modify(const int x,const int k,const int pos){erase(x,pos);tree[x]={0,0,1,x,k};root[pos]=merge(root[pos],x);}


int main()
{
	#ifndef ONLINE_JUDGE
    freopen("awa.in","r",stdin);
	freopen("awa.out","w",stdout);
	#endif
	 
	read(n,m);
	for(int i=1;i<=n;++i) read(tree[i].val),tree[i].dis=1,tree[i].fa=root[i]=i;

	int opt;ll x,y,z;
	while(m--)
		switch(read(opt))
		{
			case 0:read(x,y),erase(y,x);break;
			case 1:read(x),print(top(x),'\n');break;
			case 2:read(x,y),root[x]=merge(root[x],root[y]);break;
			case 3:read(x,y,z),modify(y,z,x);break;
		}
    
    flush();
	return 0;
}

标签:ch,read,题解,P11266,IO,print,模板,左偏
From: https://www.cnblogs.com/yunluo-qwq/p/18595163

相关文章

  • HECTF网络安全挑战赛个人题解,主Reverse部分
    ReverseezAndroid比较难的一个题。java层用rc4解出一张图片知道flag的格式so层注册了d0func和stringFromJNI两个函数其中d0func给两个全局变量赋了值,还有两个小函数也对这两个变量进行了操作,交叉引用全部找出来即可解密得到1vxyzmissonD1key和go1denG08aTJYcxk在stringFro......
  • 基于验证链(Chain of Verification)的大语言模型幻觉问题解决方案
    LLM(SEALONG:LLM(LargeLanguageModel)在长上下文推理任务中的自我改进)在生成内容时往往会遭遇一个棘手的问题——幻觉(Hallucination)。模型自信地输出虚假或误导性信息,对依赖其准确输出的开发者、工程师及用户构成了实质性的挑战。为解决这一问题,研究者提出了ChainofVerificat......
  • 牛客周赛 Round 71 题解
    牛客周赛Round71题解A构造A+B容易想出最多有\(n-1\)种构造方法,所以只要判断\(n\)和\(k\)的关系即可。#include<bits/stdc++.h>usingnamespacestd;intmain(){ intn,k;cin>>n>>k;if(k<=n-1){cout<<"YES\n";......
  • 5.1.1 C++函数模板和类模板注意事项
    一)函数注意事项·1.自动类型推导,必须推导出一致的数据类型T,才可以用。·2.模板必须要确定出T的数据类型,才可以使用。(必须给出类型表达式)二)普通函数与函数模板的区别·1.普通函数调用时可以发生自动类型转换(隐式类型转换)。·2.1函数模板调用时,如果利用“自动类型推导......
  • 你有用过哪些模板引擎?你觉得哪个好用?为什么?
    我作为一个大型语言模型,并没有真正“使用”模板引擎的方式如同前端开发者那样。我没有运行JavaScript代码或构建网页的能力。我的工作方式是基于文本的处理和生成。我更像是理解并能生成使用模板引擎的代码,而不是一个实际操作的用户。但是,我可以根据大量的代码示例和开发者讨论......
  • 模板函数使用is_same的注意事项
    在模板函数中使用is_same判断类型的话,编译器会实例化所有路径,即使某些路径在运行时不会被执行。这意味着编译器会检查所有的分支,确保它们都是有效的。例如如果存在从string转为int的路径,即便T为string时不会进入该路径,依旧会编译失败。template<classT>voidf(){ if(is_sa......
  • 【java】利用aspose.words的ReportingEngine填充word模板
    详情见:https://gitee.com/javadog-net/boot-apose前言⏲️本文阅读时长:约10分钟......
  • [题解](更新中)AtCoder Beginner Contest 383(ABC383) A~E
    A-Humidifier1照题意模拟即可,时间复杂度\(O(n)\)。点击查看代码#include<bits/stdc++.h>#defineintlonglong#defineN110usingnamespacestd;intn,t[N],v[N],sum;signedmain(){ cin>>n; for(inti=1;i<=n;i++)cin>>t[i]>>v[i]; for(inti=1......
  • CF1540B Tree Array 题解
    CF1540BTreeArray题解首先题目的时间复杂度一定是一个\(O(n^3)\)状物。一定会有一个\(n\)来枚举根节点,那么一个根内要\(O(n^2)\)地解决问题。考虑整个序列的期望是困难的,转而考虑每个点对\((x,y)\)的期望。注意到\((x,y)\)具有父子关系时,它的贡献是确定为\(0/1\)......
  • 【题解】P5787 二分图 /【模板】线段树分治
    二分图最简单的方法是染色法实现,但是扩展域并查集也可以实现,有两个集合\(S,T\),具体的是相连边的两个点\(x,y\)总是在不同的两个集合中,若出现在同一集合中即不是一个二分图。对于时间段建边考虑用线段树储存,线段树按照时间轴划分,将将对应时间区间的节点储存上当前连边操作,小时......