[学习笔记]kruskal重构树 && 并查集重构树
Kruskal 重构树
[您有新的未分配科技点][BZOJ3545&BZOJ3551]克鲁斯卡尔重构树
kruskal是一个性质优秀的算法
加入的边是越来越劣的
科学家们借这个特点尝试搞一点事情。
kruskal求最小生成树的过程,如果把加入的一个边新建一个节点的话,并且把k1,k2的father设为新点的话,会得到一个2*n大小的树
实际上已经非常明白地表示kruskal这个过程了。这个树叫kruskal重构树
每个点的权值定义为所代表的边的权值。叶子节点权值最优。
由于贪心,所以树上所有点,从儿子到祖先权值单调不优。(这是最关键的性质)
树的结构我们非常熟悉
所以各种算法纷至沓来。
具体怎么用?
BZOJ3545 Peaks:
在Bytemountains有N座山峰,每座山峰有他的高度h_i。有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走。
现在有Q组询问,每组询问询问从点v开始只经过困难值小于等于x的路径所能到达的山峰中第k高的山峰,如果无解输出-1。N<=1e5,M,Q<=5*1e5
(不强制在线的话,直接离线排序+线段树合并或者启发式合并。(类似“永无乡”))
强制在线呢?
kruskal重构树登场!
对于只走小于x的边,会得到一个可以到达的联通块。
最小生成树的边上走,保证这个联通块是极大的。
联通块高度的第k大就是答案。
发现这个联通块对应重构树的一个子树!
重构树上,从v开始往上倍增找到最后一个权值小于等于x的点p
p对应的子树的叶子就是所有的联通块的点。(有点类似SAM的fail树?)
所以区间第k大,用dfs序处理一下,+主席树维护即可。
NOI2018归程
如果想到kruskal重构树(感觉学了应该都能想到,毕竟适用面也不是很广),那么这题就水了。
所能开车到达的集合里选择距离家最近的点下车。
kruskal重构树建出来(最大生成树),叶子赋予一个dis到1的距离。
dis用dij跑(因为出题人卡spfa)
然后dfs重构树处理信息,然后倍增处理询问。大功告成!
代码:
(很丑陋,见缝插针,而且mi、dep数组其实根本不需要)
#include<bits/stdc++.h>
#define reg register int
#define il inline
#define numb (ch^'0')
using namespace std;
typedef long long ll;
il void rd(int &x){
char ch;x=;bool fl=false;
while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
for(x=numb;isdigit(ch=getchar());x=x*+numb);
(fl==true)&&(x=-x);
}
namespace Miracle{
const int N=+;
const int M=+;
const ll inf=0x3f3f3f3f3f3f3f3f;
ll dis[N];
ll ans[*N];
int val[*N];
int n,m;
struct node{
int nxt,to;
int val;
}e[*N];
int hd[*N],cnt;
void add(int x,int y,int z){
e[++cnt].nxt=hd[x];
e[cnt].to=y;
e[cnt].val=z;
hd[x]=cnt;
}
int tot;
namespace dij{ bool vis[N];
struct po{
int x,d;
po(int xx,int dd){
x=xx;d=dd;
}
bool friend operator <(po a,po b){
return a.d>b.d;
}
};
priority_queue<po>q;
void dij(){
memset(vis,,sizeof vis);
memset(dis,0x3f,sizeof dis);
while(!q.empty()) q.pop();
dis[]=;
q.push(po(,));
while(!q.empty()){
po now=q.top();q.pop();
if(vis[now.x]) continue;
vis[now.x]=;
dis[now.x]=now.d;
for(reg i=hd[now.x];i;i=e[i].nxt){
int y=e[i].to;
if(vis[y]) continue;
q.push(po(y,dis[now.x]+e[i].val));
}
}
for(reg i=;i<=n;++i){
ans[i]=dis[i];
//mi[i][0]=0x3f3f3f3f;
}
}
} struct edge{
int x,y;
int l,a;
bool friend operator <(edge a,edge b){
return a.a>b.a;
}
}b[M];
//represent the value of edge
namespace kruscal{
int fa[*N];
int fin(int x){
return fa[x]==x?x:fa[x]=fin(fa[x]);
}
void main(){
for(reg i=;i<=n;++i) {
fa[i]=i;val[i]=0x3f3f3f3f;
}
tot=n;
// cout<<" tot "<<tot<<endl;
sort(b+,b+m+);
for(reg i=;i<=m;++i){
int k1=fin(b[i].x),k2=fin(b[i].y);
// cout<<" bb "<<tot<<" "<<i<<" : "<<b[i].x<<" "<<b[i].y<<" rt "<<k1<<" sand "<<k2<<endl;
if(k1!=k2){ ++tot;
fa[tot]=tot;
ans[tot]=inf; add(tot,k1,);
add(tot,k2,);
fa[k1]=fa[k2]=tot;
val[tot]=b[i].a;
}
}
} }
int fa[*N][];
int mi[*N][];
int dep[*N]; void dfs(int x,int d){
dep[x]=d;
for(reg i=hd[x];i;i=e[i].nxt){
int y=e[i].to;
fa[y][]=x;
mi[y][]=min(val[y],val[x]);
dfs(y,d+);
ans[x]=min(ans[x],ans[y]);
}
}
ll query(int x,int p){
for(reg j=;j>=;--j){
if(fa[x][j]){
if(mi[x][j]>p) x=fa[x][j];
}
}
return ans[x];
}
void clear(){
memset(fa,,sizeof fa);
memset(mi,0x3f,sizeof mi);
memset(dep,,sizeof dep);
memset(hd,,sizeof hd);
cnt=;
}
int main(){
int T;
rd(T);
while(T--){
rd(n);rd(m);
clear();
for(reg i=;i<=m;++i){
rd(b[i].x);rd(b[i].y);rd(b[i].l);rd(b[i].a);
add(b[i].x,b[i].y,b[i].l);
add(b[i].y,b[i].x,b[i].l);
}
dij::dij();
// cout<<" after dij "<<endl; memset(hd,,sizeof hd);
cnt=;
kruscal::main();
// cout<<" after kruc "<<endl; dfs(tot,);
// cout<<" after dfs "<<endl;
for(reg j=;j<=;++j){
for(reg i=;i<=tot;++i){
fa[i][j]=fa[fa[i][j-]][j-];
mi[i][j]=min(mi[i][j-],mi[fa[i][j-]][j-]);
}
} // cout<<" tot "<<tot<<endl;
// for(reg i=1;i<=tot;++i){
// cout<<" ii "<<i<<" val "<<val[i]<<" ans "<<ans[i]<<" fafa "<<fa[i][0]<<endl;
// }
int q,k,s;
rd(q);rd(k);rd(s);
ll las=;
int v,p;
while(q--){
rd(v);rd(p);
v=(v+k*las-)%n+;
p=(p+k*las)%(s+);
printf("%lld\n",las=query(v,p));
}
}
return ;
} }
signed main(){
Miracle::main();
return ;
} /*
Author: *Miracle*
Date: 2019/1/8 18:49:37
*/
这个算法适用面:
在线处理询问在经过小于(大于)某个边权的边所能到的集合里的信息。
主要性质是祖先权值的单调不优。
这个算法是对kruskal求最小生成树的操作过程的树形结构化,从而精确剖析过程,使得维护方便。
有异曲同工之妙的是动态点分治的分治树,也是对操作过程的树形结构化。
还有一个例题:(NOI和IOI都考了诶热度真高)
[IOI2018] werewolf 狼人
upda:2019.2.13
并查集重构树
除了Kruskal重构树之外,还有一个东西叫做并查集重构树
引入例题
n个点,q次操作,每次加入一条边(不会重边自环),或者查询两个点最早什么时候连通
n,q<=1e5
(某次jzoj考试题)
还是考虑具体维护出操作的结构
用按秩合并并查集,边权就是这次加入的边的时间值
发现,两个点第一次连通,一定是两个点并查集上路径最大值!
由于按秩合并,树高logn,可以暴力查询
如果是最后询问,可以建倍增数组,loglogn复杂度
对于一般的图,边权sort,然后按照上述做即可
毒瘤一些:
1.sort用松式基排
2.并查集按秩合并+路径压缩,另外开一个邻接表记录树
接近O(n)
性质:
1.越靠上权值越劣
2.两点间最大权值就是连通时间
比较优劣
并查集重构树:
劣势:子树不是一个区间(因为没有附加点)
优势:空间小,好写好调,两点间信息可以O(loglogn)快速求出。
kruskal重构树:
反过来。
劣势:难写一些,容易写错。
优势:多了附加点,经过小于vi的边到达的区域是子树,加上dfn序列很好维护。
[学习笔记]kruskal重构树 && 并查集重构树的更多相关文章
- 【学习笔记】可持久化并查集(BZOJ3673)
好久之前就想学了 然后今天恰巧一道题需要用到就学了 前置芝士 1.主席树[可持久化数组] 2.并查集 如果你掌握了前面两个那么这个东西你就会觉得非常沙茶.. 构造 可持久化并查集 = 主席树 + 并 ...
- BZOJ3712[PA2014]Fiolki——并查集重构树
题目描述 化学家吉丽想要配置一种神奇的药水来拯救世界.吉丽有n种不同的液体物质,和n个药瓶(均从1到n编号).初始时,第i个瓶内装着g[i]克的第i种物质.吉丽需要执行一定的步骤来配置药水,第i个步骤 ...
- 【BZOJ3712】Fiolki(并查集重构树)
[BZOJ3712]Fiolki(并查集重构树) 题面 BZOJ 题解 很神仙的题目. 我们发现所有的合并关系构成了一棵树. 那么两种不同的东西如果产生反应,一定在两个联通块恰好联通的时候反应. 那么 ...
- 【web开发学习笔记】Structs2 Result学习笔记(二)动态结果集
Result学习笔记(二) - 动态结果集 动态结果 一定不要忘了为动态结果的保存值设置set get方法 第一部分:代码 //前端 <% String context = reques ...
- CF1253F Cheap Robot(神奇思路,图论,最短路,最小生成树/Kruskal 重构树/并查集)
神仙题. 先考虑平方级别的暴力怎么做. 明显答案有单调性,先二分 \(c\). 先最短路预处理 \(dis_u\) 表示 \(u\) 到离它最近的充电站的距离(一开始把 \(1\) 到 \(k\) 全 ...
- 洛谷P1991无线通讯网[kruskal | 二分答案 并查集]
题目描述 国防部计划用无线网络连接若干个边防哨所.2 种不同的通讯技术用来搭建无线网络: 每个边防哨所都要配备无线电收发器:有一些哨所还可以增配卫星电话. 任意两个配备了一条卫星电话线路的哨所(两边都 ...
- cf827D Best Edge Weight (kruskal+倍增lca+并查集)
先用kruskal处理出一个最小生成树 对于非树边,倍增找出两端点间的最大边权-1就是答案 对于树边,如果它能被替代,就要有一条非树边,两端点在树上的路径覆盖了这条树边,而且边权不大于这条树边 这里可 ...
- EF学习笔记-1 EF增删改查
首次接触Entity FrameWork,就感觉非常棒.它节省了我们以前写SQL语句的过程,同时也让我们更加的理解面向对象的编程思想.最近学习了EF的增删改查的过程,下面给大家分享使用EF对增删改查时 ...
- Docker 与 K8S学习笔记(二十三)—— Kubernetes集群搭建
小伙伴们,好久不见,这几个月实在太忙,所以一直没有更新,今天刚好有空,咱们继续k8s的学习,由于我们后面需要深入学习Pod的调度,所以我们原先使用MiniKube搭建的实验环境就不能满足我们的需求了, ...
随机推荐
- windows下Mysql安装启动及常用操作
1.下载mysql https://dev.mysql.com/downloads/ 2.配置环境变量 变量名:MYSQL_HOME 变量值:E:\MySql\mysql-8.0.15-winx64\ ...
- 415. Valid Palindrome【LintCode java】
Description Given a string, determine if it is a palindrome, considering only alphanumeric character ...
- 高可用Kubernetes集群-1. 集群环境
参考文档: 部署kubernetes集群1:https://github.com/opsnull/follow-me-install-kubernetes-cluster 部署kubernetes集群 ...
- java使用jacob将office文档转换为PDF格式
jacob 包下载地址: http://sourceforge.net/projects/jacob-project/ 下载后,将jacob 与 jacob-1.19-x64.dll放到安装jdk目录 ...
- Python异常(基础) except
为什么要异常处理机制:在程序调用层数较深时,向主调函数传递错误信息需要层层return 返回比较麻烦,用异常处理机制可以较简单的传送错误信息 什么是错误 错误是指由于逻辑或语法等导致一个程序已无法正常 ...
- nginx原声方法按照每天日志切割保存
首先配置日志变量,然后配置日志 在/etc/nginx/conf.d/default.conf 配置变量 server{ if ($time_iso8601 ~ "^(\d{4})-(\d{ ...
- preg_replace 以及弃用的e
preg_replace (PHP 4, PHP 5) preg_replace — 执行一个正则表达式的搜索和替换 说明¶ mixed preg_replace ( mixed $pattern , ...
- 作业要求20181113-4 Beta阶段第1周/共2周 Scrum立会报告+燃尽图 03
作业要求:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2385 版本控制:[https://git.coding.net/lglr201 ...
- 欢迎来怼—第二次Scrum会议
一.小组信息 队名:欢迎来怼小组成员队长:田继平成员:李圆圆,葛美义,王伟东,姜珊,邵朔,冉华小组照片 二.开会信息 时间:2017/10/14 18:30~18:47,总计17min.地点:东北师范 ...
- HDU 4055 Number String dp
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4055 Number String Time Limit: 10000/5000 MS (Java/O ...