首页 > 其他分享 >猴王 题解 || 冷门的 pb_ds 库

猴王 题解 || 冷门的 pb_ds 库

时间:2023-08-21 21:46:40浏览次数:37  
标签:__ pq gnu int 题解 find pb fa ds

猴王

前言

虽然很久以前(6月)在我们学并查集的时候 QYC 就给我们讲了左偏树可以拿来做这道题,但是左偏树作为拓展内容还是稍有难度,最近在 gcc 中看到 pb_ds 库,发现非常好用,于是就有了这种偷懒解法。

pb_ds 库

pb_ds 库是内置于 GCC 中的一种拓展标准库,可以在 CCF 系列比赛中使用。

pb_ds 库中提供了许多好用的数据结构,比如远快于 unordered_map (umap 常数太大)的 gp_hash_table (查探法)和 cc_hash_table,还有我们接下来要用到的各种不同于 STL 的配对堆、二顶堆等其它在某些方面优于二叉堆的结构,以及在 C2025 现阶段尚未学习的各种平衡树。

下面重点讲一下 pb_ds 平板电视 库中的 __gnu_pbds::priority_queue

引入

可以使用:

#include <ext/pb_ds/priority_queue.hpp>

来引入 pb_ds 的 pq,但是你也可以通过以下方式图方便:

#include <bits/extc++.h>
using namespace std;
using namespace __gnu_cxx;
using namespace __gnu_pbds;

一次性导入包括 std:: 在内的所有 GCC 内置库。

上面的 bits/extc++.h 在 TDM-GCC 下会报错,需要手动找到文件(编译器会提示)删除这一段:

#ifdef _GLIBCXX_HAVE_ICONV
 #include <ext/codecvt_specializations.h>
 #include <ext/enc_filebuf.h>
#endif

使用

使用以下方式来定义一个大根堆(比起STL少一个定义堆存储类型的参数,多一个类型声明):

__gnu_pbds::priority_queue<type,less<type>,pairing_heap_tag> //避免和stl混淆,pairing_heap_tag表示声明配对堆,可以合并
//有pairing_heap_tag binary_heap_tag binomial_heap_tag rc_binomial_heap_tag thin_heap_tag
//实测pairing_heap_tag在本题中表现最优秀,二叉堆会TLE,具体可以参考下文OIWiki
//实际上是可以缺省的
__gnu_pbds::priority_queue<type>

大体上和 STL 差不多,只不过支持了 Remove()Modify()Merge() 操作:

Merge 复杂度 \(O(1)\)

a.join(b); //将b并入a,b清空,两堆类型需要一致

Remove 和 Modify 需要迭代器支持:

auto it=pq.push(114514); //push返回元素迭代器
pq.modify(it,1919810); //修改114514为1919810
pq.remove(it); //删除1919810

其它部分可以参见:https://oi-wiki.org/lang/pb-ds/pq/

解析

知道了可并堆的用法,我们就可以做这道题了。

我采用了这样的方案:维护一个数组 pq a[] 存储每一个猴子所在集合的朋友,再维护一个并查集来映射每一个猴子所在的集合,每次争斗后取出堆顶各自减半,再将两猴子的堆合并到第一个猴子那边,并合并并查集即可。

这样是不是比左偏树什么的简单多了qwq

代码

下面是这道题的代码,其实也就很简单了

注释版

#include <bits/extc++.h>
using namespace std;
using namespace __gnu_pbds;
using namespace __gnu_cxx;
__gnu_pbds::priority_queue<int> pq[100005]; //这里要防止命名冲突,后面缺省即可
int n,m,fa[100005]; 
int find(int x){ //并查集板子
    return fa[x]==x?x:fa[x]=find(fa[x]);
}
inline void merge(int x,int y){
    int u=find(x),v=find(y);
    if(x!=y) fa[v]=u;
}
int main(){
    ios::sync_with_stdio(0);
    cin>>n,iota(fa,fa+1+n,0); //STL函数,连续给fa进行范围赋值
    for(int i=1,t;i<=n;i++)
        cin>>t,pq[i].push(t); //初始时各自为一个集合
    cin>>m;
    for(int i=1,x,y,t;i<=m;i++){
        cin>>x>>y;
        //两方各自取出堆顶并减半放回去(其实可以用modify但是稍微麻烦)
        t=pq[find(x)].top(),pq[find(x)].pop(),pq[find(x)].push(t/2);
        t=pq[find(y)].top(),pq[find(y)].pop(),pq[find(y)].push(t/2);
        //合并两个堆和并查集
        pq[find(x)].join(pq[find(y)]),merge(x,y);
        //输出最后的堆顶即可
        cout<<pq[find(x)].top()<<endl;
    }
    return 0;
}
//写完了awa

极速版

#include <bits/extc++.h>
using namespace std;
using namespace __gnu_pbds;
using namespace __gnu_cxx;
__gnu_pbds::priority_queue<int> pq[100005];
int n,m,fa[100005];
int find(int x){
    return fa[x]==x?x:fa[x]=find(fa[x]);
}
inline void merge(int x,int y){
    int u=find(x),v=find(y);
    if(x!=y) fa[v]=u;
}
int main(){
    ios::sync_with_stdio(0);
    cin>>n,iota(fa,fa+1+n,0);
    for(int i=1,t;i<=n;i++)
        cin>>t,pq[i].push(t);
    cin>>m;
    for(int i=1,x,y,t;i<=m;i++){
        cin>>x>>y;
        t=pq[find(x)].top(),pq[find(x)].pop(),pq[find(x)].push(t/2);
        t=pq[find(y)].top(),pq[find(y)].pop(),pq[find(y)].push(t/2);
        pq[find(x)].join(pq[find(y)]),merge(x,y);
        cout<<pq[find(x)].top()<<endl;
    }
    return 0;
}

标签:__,pq,gnu,int,题解,find,pb,fa,ds
From: https://www.cnblogs.com/LYXOfficial/p/17647160.html

相关文章

  • 「NOIP2017 普及组」棋盘 题解
    前言一个绿题,风光啊QwQ题面传送门思路怎么走我们定义一个函数dfs(x,y,coin,can,color)x,y表示坐标,coin表示当前的金币数量,color表示当前坐标的颜色,can表示当前是否能施展魔法。再加一个mp数组记录颜色,-1表示无颜色,0表示红色,1表示黄色为什么不直接使用mp[x][y]获取颜......
  • [CF1790F] Timofey and Black-White Tree 题解
    [CF1790F]TimofeyandBlack-WhiteTree题解题目描述ZYH有一棵\(n\)个节点的树,最初\(c_0\)号节点是黑色,其余均为白色。给定操作序列\(c_1,c_2,\cdots,c_{n-1}\),第\(i\)次操作表示将\(c_i\)号节点染黑。每次操作后,输出距离最近的两个黑点间的距离。两点\(u,v\)间......
  • CF1762E Tree Sum 题解
    题意对于一棵\(n\)个节点的树\(T\),定义\(\operatorname{good}(T)\)为真当且仅当边权\(w\in\left\{-1,1\right\}\)且对于任意节点\(u\),均有\(\displaystylef(u)=\prod\limits_{\left(u,v\right)\inE}w\left(u,v\right)=-1\)。求\[\sum\limits_{\operat......
  • Raspberry Pi 内网穿透实战教程 All In One
    RaspberryPi内网穿透实战教程AllInOne树莓派使用场景使用RaspberryPi搭建个人Web项目的服务器,并且提供外网访问的能力(Web,SSH)数据安全,私有代码低成本服务器容器化微服务全栈开发demos(......
  • RTSP/Onvif视频服务器EasyNVR安防视频云服务调用接口录像会被自动删除的问题解决方案
    EasyNVR安防视频云服务是基于RTSP/Onvif协议接入的视频平台,可支持将接入的视频流进行全平台、全终端的分发,分发的视频流包括RTSP、RTMP、HTTP-FLV、WS-FLV、HLS、WebRTC等。平台丰富灵活的视频能力,可应用在智慧校园、智慧工厂、智慧水利等场景中。有用户反馈,在使用EasyNVR接入设备......
  • [ABC315G] Ai + Bj + Ck = X (1 <= i, j, k <= N) 题解
    [ABC315G]Ai+Bj+Ck=X(1<=i,j,k<=N)题解题目描述求题目中式子的数量。思路因为\(N\le10^6\),所以考虑枚举\(k\),那么变为求\(ai+bj=x-ck,i,j\in[1,N]\),这个问题可以通过Exgcd算法求解。首先考虑求出一组\(i,j\)的特解\(x',y'\),根据通解\(x=x'+......
  • Codeforces Round 893 (Div. 2) A-C题解
    CF893(Div.2)A.Buttons签到题。两人会优先选择c中的按钮来,避免自己的按钮消耗同时减少对方可选择的按钮。所以c%2==1等价于a的按钮数+1,c%2==0时相当于c按钮不存在,比较ab按钮的数量来得出答案即可。#include<iostream>usingnamespacestd;typedeflonglong......
  • 跨版本迁移数据报错tables declared WITH OIDS are not supported
    瀚高数据库目录环境症状问题原因解决方案环境系统平台:Linuxx86-64RedHatEnterpriseLinux7版本:6.0症状迁移数据还原数据库时报错ERROR:tablesdeclaredWITHOIDSarenotsupported问题原因Postgresql12后取消了OIDS=TRUE的用法。解决方案修改脚本中的语句脚本中出现OIDS=T......
  • [AGC005C] Tree Restoring 题解
    比较简单的题。思路我们可以把一棵树抽象成一条极长的链上挂了很多的点。观察这样的树的性质。除去中间的每一个\(dis\)至少有两个点的\(a_i=dis\)。考虑这条链的长度为\(s\)。那么对于中间的点,我们可以分两种情况讨论。\(s\)为偶数那么我们必然要求在中间的权值只......
  • hive sql运行时候reduce 只有2个问题解决
    我们在explansql时候发现width是负数,事实上原因width是通过dataSize/rowNum计算出来的,这两个参数都是在执行计划中根据每个operator通过stats计算出来的。对于selectquery来说,datasize是根据columnstats、尤其是non-null的数据计算出来的,这些non-nullvalue按照如下公......