zoukankan      html  css  js  c++  java
  • 【BZOJ1455】罗马游戏(简单重拾左偏树)

    点此看题面

    大致题意: 左偏树板子。给定(n)个数,两种操作:合并两堆数;询问并删除某堆数中的最小值。

    前言

    暂时脱离网络流的苦海,写道水题轻松一下。。。

    为什么会来做这道题?因为提交完另一道题后正好机房里有人在写此题,主要是看到了罗马,想着好久没写过左偏树了,就来写发板子。

    大致想法

    板子题还能有啥想法。。。。。。

    只是用并查集维护连通性的时候,突发奇想用并查集的老祖宗来记录每个点所在左偏树的根,然后发现这样只要查询祖先就能求出堆中的最小值。于是最后就变成了用左偏树来维护并查集???(怎么感觉哪里不太对劲,可仔细一想又没啥问题emmm)

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 1000000
    #define swap(x,y) (x^=y^=x^=y)
    using namespace std;
    int n,a[N+5],p[N+5];
    class FastIO
    {
    	private:
    		#define FS 100000
    		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
    		#define pc(c) (C==E&&(clear(),0),*C++=c)
    		#define D isdigit(c=tc())
    		int T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
    	public:
    		I FastIO() {A=B=FI,C=FO,E=FO+FS;}
    		Tp I void read(Ty& x) {x=0;W(!D);W(x=(x<<3)+(x<<1)+(c&15),D);}
    		I void readc(char& x) {W(isspace(x=tc()));}
    		Tp I void writeln(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);pc('
    ');}
    		I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
    		#undef D
    }F;
    class UnionFindSet//神奇的并查集
    {
    	private:
    		int f[N+5];
    	public:
    		I void Init() {for(RI i=1;i<=n;++i) f[i]=i;}//初始化
    		I int fa(CI x) {return f[x]^x?f[x]=fa(f[x]):x;}//找老祖宗
    		I void Union(CI x,CI y) {f[y]=x;}//合并
    		I void Upt(CI x,CI y) {f[x]=f[y]=y;}//修改老祖宗(左偏树弹去堆顶后要修改根)
    }U;
    class LeftistTree//左偏树(用于维护并查集?)
    {
    	private:
    		struct node {int F,D,S[2];I node() {F=D=S[0]=S[1]=0;}}O[N+5];
    		I int Merge(RI x,RI y)//合并
    		{
    			if(!x||!y) return x|y;a[x]>a[y]&&swap(x,y),O[x].S[1]=Merge(O[x].S[1],y),
    			O[O[x].S[1]].F=x,O[O[x].S[1]].D>O[O[x].S[0]].D&&swap(O[x].S[0],O[x].S[1]);
    			return O[x].D=O[O[x].S[1]].D+1,x;
    		}
    	public:
    		I LeftistTree() {O[0].D=-1;}
    		I void Union(CI x,CI y) {a[x]<a[y]?U.Union(x,y):U.Union(y,x),Merge(x,y);}//合并,使并查集的老祖宗为权值较小的点(即堆顶)
    		I void Pop(CI x)//弹出堆顶
    		{
    			p[x]=1,O[x].D=-1,O[O[x].S[0]].F=O[O[x].S[1]].F=0;//消除在左偏树上留下的痕迹
    			RI y=Merge(O[x].S[0],O[x].S[1]);y&&(U.Upt(x,y),0);//把并查集中x所在连通块的老祖宗修改为当前根
    		}
    }T;
    int main()
    {
    	RI i;for(F.read(n),i=1;i<=n;++i) F.read(a[i]);U.Init();
    	RI Qt,x,y,fx,fy;char op;F.read(Qt);W(Qt--) switch(F.readc(op),F.read(x),op)
    	{
    		case 'M':F.read(y),!p[x]&&!p[y]&&//如果都没被删掉
    			(fx=U.fa(x))^(fy=U.fa(y))&&(T.Union(fx,fy),0);break;//不在同一堆中便合并
    		case 'K':!p[x]?(F.writeln(a[y=U.fa(x)]),T.Pop(y)):F.writeln(0);break;//输出老祖宗的权值,然后弹出堆顶
    	}return F.clear(),0;
    }
    
  • 相关阅读:
    tomcat安装配置
    Java的jdk环境变量配置
    我为什么在这里写博客
    函数
    java的内部类解析
    常用集合
    java数据类型总结
    Java总结基础知识
    线程的状态和方法
    java对象序列化的理解
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ1455.html
Copyright © 2011-2022 走看看