[您有新的未分配科技点][BZOJ3545BZOJ3551]克鲁斯卡尔重构树
这次我们来搞一个很新奇的知识点:克鲁斯卡尔重构树。它也是一种图,是克鲁斯卡尔算法求最小生成树的升级版首先看下面一个问题:BZOJ3545 Peaks。
在Bytemountains有N座山峰,每座山峰有他的高度h_i。有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走。
现在有Q组询问,每组询问询问从点v开始只经过困难值小于等于x的路径所能到达的山峰中第k高的山峰,如果无解输出-1。N<=1e5,M,Q<=5*1e5
上面这个题没有要求在线,因此我们可以离线构造最小生成树,然后当小于等于一个询问的困难值的所有边都加入后,就可以查询当前的询问点。
这种操作只需要主席树上树+启发式合并就可以解决了。(参考资料:主席树上树http://www.cnblogs.com/LadyLex/p/7275164.html,启发式合并http://www.cnblogs.com/LadyLex/p/7275793.html)
但是如果强制在线呢?BZOJ3551 Peaks加强版,在上一题基础上强制在线。
可以用来解决一系列“查询从某个点出发经过边权不超过val的边所能到达的节点”的问题,可以和其他数据结构(比如主席树)套用来维护更加复杂的询问。
克鲁斯卡尔重构树的核心思想是,当添加最小生成树中的边的时候,不在两个点间直接加边,而是新建节点,让边的两个端点所在的联通块的代表点分别作为它的左右儿子节点,然后这个新建的点,就成为这整个连通块的代表点,点权为连边的值(最开始n个叶子节点点权为0)。比如看下面这张图:首先连接(1,2),新建一个点5。再连接(3,4),新建一个点6。然后连接(1,3),连接它们各自联通块的代表点(5,6),再新建一个点7。
这样得到的树有一个很优雅的性质:一个点的所有子树节点的权值都小于等于它的权值,并且从它开始逐渐向子节点移动,权值是单调不上升的。这个性质是显然的,因为我们在构造树的时候是从小到大插入的边,因此父亲节点的权值一定大于等于子节点的值。
查询时,首先可以在树上倍增得到当前查询点所能够到达的最远的祖先点,那么从这个点能够到达的符合边权限制条件的连通块中的节点,就是祖先点的子树中所有的叶节点。
然后我们按dfs序维护一个主席树上树就可以解决了。
代码见下:
1 #include <cstring> 2 #include <cstdio> 3 #include <algorithm> 4 #include <ctime> 5 using namespace std; 6 const int N=100100; 7 int h[N*2],val[N*2],n,tot,num,cnt,stack[N],e,adj[N*2]; 8 int f[N*2][20],bin[25],fa[N*2],l[N*2],r[N*2]; 9 struct edge{int qi,zhong,val;}intn[N*5]; 10 struct link{int zhong,next;}s[N*2]; 11 inline void mission1(int rt){for(int i=1;bin[i]<=n;i++)f[rt][i]=f[f[rt][i-1]][i-1];} 12 inline void add(int qi,int zhong){s[++e].zhong=zhong;s[e].next=adj[qi];adj[qi]=e;} 13 inline bool mt(const edge &a,const edge &b){return a.val<b.val;} 14 int find(int a){return (fa[a]==a)?a:fa[a]=find(fa[a]);} 15 struct node 16 { 17 int cnt;node *ch[2]; 18 node(){cnt=0;ch[0]=ch[1]=NULL;} 19 inline void update(){cnt=ch[0]->cnt+ch[1]->cnt;} 20 }*null=new node(),*root[2*N]; 21 inline node* newnode(){node *o=new node();o->ch[0]=o->ch[1]=null;return o;} 22 void insert(node *&o,node *old,int l,int r,int pos) 23 { 24 o->cnt=old->cnt+1; 25 if(l==r)return; 26 int mi=(l+r)>>1; 27 if(pos<=mi)o->ch[1]=old->ch[1],o->ch[0]=newnode(),insert(o->ch[0],old->ch[0],l,mi,pos); 28 else o->ch[0]=old->ch[0],o->ch[1]=newnode(),insert(o->ch[1],old->ch[1],mi+1,r,pos); 29 o->update(); 30 } 31 inline int query(int a,int x,int k) 32 { 33 int le=1,ri=tot; 34 for(int j=18;~j;j--) 35 if(f[a][j]&&val[f[a][j]]<=x)a=f[a][j]; 36 node *a1=root[r[a]],*a2=root[l[a]-1]; 37 if(a1->cnt-a2->cnt<k)return -1; 38 while(le<ri) 39 { 40 int tmp=a1->ch[1]->cnt-a2->ch[1]->cnt,mi=(le+ri)>>1; 41 if(tmp>=k)a1=a1->ch[1],a2=a2->ch[1],le=mi+1; 42 else a1=a1->ch[0],a2=a2->ch[0],k-=tmp,ri=mi; 43 } 44 return stack[ri]; 45 } 46 void dfs(int rt) 47 { 48 mission1(rt);l[rt]=++num; 49 if(rt<=n)insert(root[num],root[num-1],1,tot,h[rt]); 50 else root[num]=root[num-1]; 51 for(int i=adj[rt];i;i=s[i].next)dfs(s[i].zhong); 52 r[rt]=num; 53 } 54 int main() 55 { 56 int m,q,ans=0,v,x,k;scanf("%d%d%d",&n,&m,&q); 57 bin[0]=1;for(int i=1;i<=22;i++)bin[i]=bin[i-1]<<1; 58 null->ch[0]=null->ch[1]=null; 59 for(int i=1;i<=n*2;i++)fa[i]=i; 60 for(int i=1;i<=n;i++)scanf("%d",&h[i]),stack[i]=h[i]; 61 for(int i=1;i<=m;i++)scanf("%d%d%d",&intn[i].qi,&intn[i].zhong,&intn[i].val); 62 sort(stack+1,stack+n+1); 63 tot=unique(stack+1,stack+n+1)-stack-1; 64 for(int i=1;i<=n;i++)h[i]=lower_bound(stack+1,stack+tot+1,h[i])-stack; 65 sort(intn+1,intn+m+1,mt);cnt=n; 66 for(int i=1;i<=m;i++) 67 { 68 int u=find(intn[i].qi),v=find(intn[i].zhong); 69 if(u!=v) 70 { 71 val[++cnt]=intn[i].val,fa[u]=fa[v]=cnt; 72 add(cnt,u),add(cnt,v),f[u][0]=f[v][0]=cnt; 73 if(cnt-n==n-1)break; 74 } 75 } 76 for(int i=0;i<=cnt;i++)root[i]=newnode(); 77 for(int i=1;i<=cnt;i++)if(!l[i])dfs(find(i)); 78 while(q--) 79 { 80 scanf("%d%d%d",&v,&x,&k); 81 if(ans!=-1)v^=ans,x^=ans,k^=ans;/*去掉这句强制在线可以ACbzoj3545*/ 82 printf("%d\n",ans=query(v,x,k)); 83 } 84 }
克鲁斯卡尔重构树是个比较小众的知识点,但在处理对口的操作时十分强大。下次你再看到类似询问的时候,不妨想一想克鲁斯卡尔重构树,也许就会柳暗花明又一村:)
转载于:https://www.cnblogs.com/LadyLex/p/7275821.html
[您有新的未分配科技点][BZOJ3545BZOJ3551]克鲁斯卡尔重构树相关推荐
- [您有新的未分配科技点]可,可,可持久化!?------0-1Trie和可持久化Trie普及版讲解...
这一次,我们来了解普通Trie树的变种:0-1Trie以及在其基础上产生的可持久化Trie(其实,普通的Trie也可以可持久化,只是不太常见) 先简单介绍一下0-1Trie:一个0-1Trie节点只有 ...
- 【您有新的未分配天赋点】网络流:从懵逼到完全懵逼
今天呢@assassain julao讲了一个在OI中极其重要,极其有趣,把无数人坑退役的知识点:网络流. 网络流呢顾名思义,就是在一个图中边有流量的限制,并根据这些流量限制做一些跟这个有关的事(ti ...
- win10可用空间变成未分配_教你两种方法有效利用Win10未分配的空间 - 易我科技...
Haley 于 2020/08/24更新 磁盘分区管理 摘要 文中介绍了两种方法充分利用Windows10未分配空间,分别为1)格式化Win10未分配空间来创建新的分区,2)在分区上添加未分配空间. ...
- centos7 转换为lvm_(建议收藏)CentOS7挂载未分配的磁盘空间以及LVM详细介绍
简述 本文主要介绍CentOS7下如何挂载未分配磁盘空间的详细操作步骤. LVM LVM,逻辑卷管理,英文全称Logical Volume Manager,是Linux环境下对磁盘分区进行管理的一种机 ...
- 【Elasticsearch】es 集群健康值 红色 red 分片 未分配
1.概述 转载:https://zhuanlan.zhihu.com/p/101608973 转载这篇文章是因为根据我的文章 [Elasticsearch]elasticsearch 7.x 查看分片 ...
- win10可用空间变成未分配_有关如何在win10系统中对未分配的磁盘空间进行分区的详细教程...
win10系统已经使用了很长时间,许多网民都报告了对win10系统未分配磁盘空间进行分区的方法. 在使用win10系统的过程中,他们通常不知道如何对win10系统的未分配磁盘空间进行分区. 对于设置, ...
- centos7.5系统动态扩容磁盘及系统挂载未分配硬盘空间
一.系统动态扩容磁盘 系统 原磁盘大小 扩容大小 centos7.5 20G 18G 本次实验为虚拟机,首先看看本机原来的磁盘大小 [root@123 ~]# lsblk NAME MAJ:MIN R ...
- 教你如何将磁盘中黑色的未分配空间变成绿色的可用空间
在黑色的未分配空间上建立新的卷 使用分区助手或者DiskGenius将新建立的卷从主分区转换成逻辑分区 在磁盘管理中删除这个卷,然后就会变成绿色的空用空间
- 硬盘显示未分配时怎么恢复硬盘数据
硬盘显示未分配是什么意思?以win10系统为例,首先我们鼠标右击桌面上的此电脑,点击管理按钮.打开计算机管理,点击磁盘管理,能够看到电脑上的硬盘及分区情况. 而未分配的磁盘会直接显示磁盘"未 ...
- win10可用空间变成未分配_Win10专业版下第二个硬盘未分配,如何解决?
有时您可能会在PC上遇到硬盘未分配的消息.如果发生这种情况,您将无法访问您的硬盘驱动器或任何文件.这可能是一个大问题,但您可以使用我们的解决方案解决它. 如果您的第二个硬盘驱动器未分配,则可能无法正常 ...
最新文章
- invertible Conditional GANs for image editing
- 使用预训练的卷积神经网络(猫狗图片分类)
- 【MM模块】Invoice Verification in the Background 后台发票校验
- linux lanmp 安装教程,linux服务器一键安装包lanmp系列教程之一
- 痞子衡嵌入式:第一本Git命令教程(0)- 索引
- Loj#6247-九个太阳【单位根反演】
- layui结合ajax实现下拉菜单联动效果
- 数据3分钟丨CSDN 1024程序员节来啦!PostgreSQL 14和openGauss 2.1.0在同一天正式发布。...
- 全球最快65W闪充!OPPO Reno Ace正式发布 高达限量定制版售价仅3599元
- 电脑怎么装linux系统
- Cartesian coordinate system
- ip后面带端口号如何做域名解析
- 列表xcode项目下所有的lnfo.plist
- 【人工智能 AI】什么是人工智能? What is Artificial Intelligence
- 手游自动化测试基础:方法及流程
- 区间DP小结(附经典例题)
- git clone使用指定用户名和密码
- 华为hcie认证-QOS 流量整形双速率的概念
- 45-互联网安全架构-Web常用攻击手段之XSS脚本SQL注入攻击
- 蓝桥杯按键处理解决办法
热门文章
- STL总结笔记(实用 / 比赛)
- linux下查看进程与线程
- 另一种阶乘 函数法!
- 【算法笔记】求给定序列的第k大(权值线段树/直接离散化)
- clion小白使用技巧(持续更新中)
- c++线程类 linux,C++进阶学习——线程基类的设计(Linux)
- hbase 查询某列_hbase shell使用STARTROW、ENDROW、FILTER查出指定的列
- ML for trading -cs7646-02
- 机器学习- 吴恩达Andrew Ng - week3-3 Multiclass Classification
- ubuntu mysql 连接数_ubuntu-阿里云下 Tomcat 应用无法连接数Mysql据库