BZOJ3732Network——kruskal重构树+倍增+LCA/最小生成树+倍增
题目描述
给你N个点的无向图 (1 <= N <= 15,000),记为:1…N。
图中有M条边 (1 <= M <= 30,000) ,第j条边的长度为: d_j ( 1 < = d_j < = 1,000,000,000).
现在有 K个询问 (1 < = K < = 20,000)。
每个询问的格式是:A B,表示询问从A点走到B点的所有路径中,最长的边最小值是多少?
输入
第一行: N, M, K。
第2..M+1行: 三个正整数:X, Y, and D (1 <= X <=N; 1 <= Y <= N). 表示X与Y之间有一条长度为D的边。
第M+2..M+K+1行: 每行两个整数A B,表示询问从A点走到B点的所有路径中,最长的边最小值是多少?
输出
对每个询问,输出最长的边最小值是多少。
样例输入
1 2 5
2 3 4
3 4 3
1 4 8
2 5 7
4 6 2
1 2
1 3
1 4
2 3
2 4
5 1
6 2
6 1
样例输出
5
5
4
4
7
4
5
提示
1 <= N <= 15,000
1 <= M <= 30,000
1 <= d_j <= 1,000,000,000
1 <= K <= 15,000
首先根据最小生成树的性质可以知道两点间路径上最长边最小的那条路径,就是最小生成树上两点间的路径——因为最小生成树是按边权从小到大加边,所以保证两点间路径上的边都尽可能的小。那么只要先把最小生成树求出来,其他的边就没有用了。对于最小生成树求解,一种做法是倍增维护g[i][j]表示以i节点向上跳2j步路径上的边权最大值。今天来介绍另一种做法——kruskal重构树。什么是kruskal重构树呢?就是把最小生成树上的边从小到大,对于每一条边a-b边权为c,就把重构树上a所在子树的根节点和b所在子树的根节点(可以是自己)分别连到一个新建节点上,将那个点作为这两个点的父节点,而新建那个点的点权就是c。最后形成的一棵二叉树就是kruskal重构树。kruskal重构树是一个大根堆且两叶子节点的lca点权就是这两点在最小生成树上路径上的最大边权。这样对于每次询问只要找到两点lca就行了。
最小生成树+倍增
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
int n,m;
int next[100050];
int to[100050];
int val[100050];
int head[15010];
int f[15010][20];
int g[15010][20];
int d[15010];
int F[15010];
int tot=0;
int sum;
int num;
struct node
{
int x;
int y;
int v;
}a[50001];
void add(int x,int y,int v)
{
tot++;
next[tot]=head[x];
head[x]=tot;
to[tot]=y;
val[tot]=v;
}
int cmp(node a,node b)
{
return a.v<b.v;
}
int find(int x)
{
if(F[x]==x)
{
return x;
}
return F[x]=find(F[x]);
}
void dfs(int x,int fx)
{
f[x][0]=fx;
d[x]=d[fx]+1;
for(int j=1;(1<<j)<=n;j++)
{
f[x][j]=f[f[x][j-1]][j-1];
g[x][j]=max(g[f[x][j-1]][j-1],g[x][j-1]);
}
for(int i=head[x];i;i=next[i])
{
if(to[i]!=fx)
{
g[to[i]][0]=val[i];
dfs(to[i],x);
}
}
}
int lca(int x,int y)
{
int total=0;
if(d[x]<d[y])
{
swap(x,y);
}
int deep=d[x]-d[y];
for(int i=0;i<=18;i++)
{
if((deep&(1<<i))!=0)
{
total=max(total,g[x][i]);
x=f[x][i];
}
}
if(x==y)
{
return total;
}
for(int j=18;j>=0;j--)
{
if(f[x][j]!=f[y][j])
{
total=max(total,max(g[x][j],g[y][j]));
x=f[x][j];
y=f[y][j];
}
}
return total=max(max(g[x][0],g[y][0]),total);
}
int main()
{
scanf("%d%d",&n,&m);int q;scanf("%d",&q);
for(int i=1;i<=n;i++)
{
F[i]=i;
}
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].v);
}
sort(a+1,a+1+m,cmp);
num=0;
sum=0;
for(int j=1;j<=m;j++)
{
int fx=find(a[j].x);
int fy=find(a[j].y);
if(fx!=fy)
{
F[fx]=fy;
num++;
sum+=a[j].v;
add(a[j].x,a[j].y,a[j].v);
add(a[j].y,a[j].x,a[j].v);
}
if(num==n-1)
{
break;
}
}
g[1][0]=0;
dfs(1,1);
int A,B;
for(int i=1;i<=q;i++)
{
scanf("%d%d",&A,&B);
printf("%d\n",lca(A,B));
}
}
kruskal重构树
#include<map>
#include<set>
#include<queue>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
struct node
{
int x;
int y;
int z;
}a[30010];
int cnt;
int tot;
int A,B;
int n,m,k;
int d[30010];
int fa[15010];
int ga[30010];
int to[100010];
int head[100010];
int next[100010];
int f[30010][17];
int g[30010];
void add(int x,int y)
{
tot++;
next[tot]=head[x];
head[x]=tot;
to[tot]=y;
}
int get(int x)
{
if(ga[x]==x)
{
return x;
}
return ga[x]=get(ga[x]);
}
int find(int x)
{
if(fa[x]==x)
{
return x;
}
return fa[x]=find(fa[x]);
}
bool cmp(node a,node b)
{
return a.z<b.z;
}
void dfs(int x,int fa)
{
d[x]=d[fa]+1;
for(int i=1;i<=16;i++)
{
f[x][i]=f[f[x][i-1]][i-1];
}
for(int i=head[x];i;i=next[i])
{
if(to[i]!=fa)
{
dfs(to[i],x);
}
}
}
int lca(int x,int y)
{
if(d[x]<d[y])
{
swap(x,y);
}
int dep=d[x]-d[y];
for(int i=0;i<=16;i++)
{
if((dep&(1<<i))!=0)
{
x=f[x][i];
}
}
for(int i=16;i>=0;i--)
{
if(f[x][i]!=f[y][i])
{
x=f[x][i];
y=f[y][i];
}
}
x=f[x][0];
return g[x];
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)
{
fa[i]=i;
}
for(int i=1;i<=2*n;i++)
{
ga[i]=i;
}
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
}
sort(a+1,a+1+m,cmp);
cnt=n;
for(int i=1;i<=m;i++)
{
int fx=find(a[i].x);
int fy=find(a[i].y);
if(fx!=fy)
{
fa[fx]=fy;
cnt++;
int gx=get(a[i].x);
int gy=get(a[i].y);
g[cnt]=a[i].z;
ga[gx]=cnt;
ga[gy]=cnt;
f[gx][0]=cnt;
f[gy][0]=cnt;
add(gx,cnt);
add(cnt,gx);
add(gy,cnt);
add(cnt,gy);
}
}
dfs(cnt,cnt);
for(int i=1;i<=k;i++)
{
scanf("%d%d",&A,&B);
printf("%d\n",lca(A,B));
}
}
BZOJ3732Network——kruskal重构树+倍增+LCA/最小生成树+倍增的更多相关文章
- 水壶-[Kruskal重构树] [解题报告]
水壶 本来从不写针对某题的题解,但因为自己实在是太蠢了,这道题也神TM的恶心,于是就写篇博客纪念一下 H水壶 时间限制 : 50000 MS 空间限制 : 565536 KB 评测说明 : 2s,51 ...
- 【BZOJ 3732】 Network Kruskal重构树+倍增LCA
Kruskal重构树裸题, Sunshine互测的A题就是Kruskal重构树,我通过互测了解到了这个神奇的东西... 理解起来应该没什么难度吧,但是我的Peaks连WA,,, 省选估计要滚粗了TwT ...
- 【BZOJ-3545&3551】Peaks&加强版 Kruskal重构树 + 主席树 + DFS序 + 倍增
3545: [ONTAK2010]Peaks Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1202 Solved: 321[Submit][Sta ...
- BZOJ5415[Noi2018]归程——kruskal重构树+倍增+堆优化dijkstra
题目描述 本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定. 魔力之都可以抽象成一个 n 个节点.m 条边的无向连通图(节点的编号从 1 至 n).我们依次用 l,a 描述一条边的长度.海 ...
- BZOJ3545&3551[ONTAK2010]Peaks——kruskal重构树+主席树+dfs序+树上倍增
题目描述 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只 ...
- LOJ #2718. 「NOI2018」归程(Dijkstra + Kruskal重构树 + 倍增)
题意 给你一个无向图,其中每条边有两个值 \(l, a\) 代表一条边的长度和海拔. 其中有 \(q\) 次询问(强制在线),每次询问给你两个参数 \(v, p\) ,表示在 \(v\) 出发,能开车 ...
- Gym - 101173H Hangar Hurdles (kruskal重构树/最小生成树+LCA)
题目大意:给出一个n*n的矩阵,有一些点是障碍,给出Q组询问,每组询问求两点间能通过的最大正方形宽度. 首先需要求出以每个点(i,j)为中心的最大正方形宽度mxl[i][j],可以用二维前缀和+二分或 ...
- UVA1265 Tour Belt Kruskal重构树、倍增、树上差分
题目传送门 题意:定义$Tour \, Belt$为某张图上的一个满足以下条件的点集:①点集中至少有$2$个点②任意两点互相连通③图上两个端点都在这个点集中的边的权值的最小值严格大于图上只有一个端点在 ...
- [SCOI2013]摩托车交易 kruskal重构树(最大生成树) 倍增
---题面--- 题解: 这题想法简单,,,写起来真的是失智,找了几个小时的错误结果是inf没开到LL范围.... 首先我们需要找到任意两点之间能够携带黄金的上限值,因为是在经过的道路权值中取min, ...
随机推荐
- Android学习之基础知识三(Android日志工具Log的使用)
Android中的日志工具Log(android.util.Log): 1.打印日志的方法(按级别从低到高排序): Log.v():级别verbose,用于打印最为烦琐,意义最小的日志 Log.d() ...
- http一次请求过程
物理层:支持底层网络协议: 其中网络层支持IP协议: 传输层支持TCP协议,它是面向连接的: 应用层支持 http,ftp tftp,SMTP,DHCP协议 一个完整的http请求过程: 1.浏览器 ...
- CF101D Castle 树形DP、贪心
题目传送门 题意:给出一个有$N$个点的树,你最开始在$1$号点,经过第$i$条边需要花费$w_i$的时间.每条边只能被经过$2$次.求出到达除$1$号点外所有点的最早时间的最小平均值.$N \leq ...
- WPF 任务栏背景闪烁提醒
原文:WPF 任务栏图标闪烁提醒 public static class FlashWindow { [DllImport("user32.dll")] [return: Ma ...
- Scala学习(四)---映射和元组
映射和元组 摘要: 一个经典的程序员名言是:"如果只能有一种数据结构,那就用哈希表吧".哈希表或者更笼统地说映射,是最灵活多变的数据结构之一.映射是键/值对偶的集合.Scala有一个通用的叫法:元组, ...
- Part 5:Django测试--Django从入门到精通系列教程
该系列教程系个人原创,并完整发布在个人官网刘江的博客和教程 所有转载本文者,需在顶部显著位置注明原作者及www.liujiangblog.com官网地址. 本节将简要介绍Django的自动化测试相关内 ...
- 学习ML.NET(2): 使用模型进行预测
训练模型 在上一篇文章中,我们已经通过LearningPipeline训练好了一个“鸢尾花瓣预测”模型, var model = pipeline.Train<IrisData, IrisPre ...
- JAVA中使用MD5加密实现密码加密
1.新建Md5.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package c ...
- linux-shell-命令总结
第一种方法执行: 第二种方法执行: 第三种方法执行: 第四种方法:执行 第三种和第四种方法都是在新的进程里执行程序 函数方法 方法就是一个命令,命令写在字符串的第一个位置 type:可以接外部命令 ...
- package.json中的几种依赖注册对象解析
本博文根据官网+google翻译+自己的理解,欢迎指出翻译的不到位的地方. package.json的重要性不言而喻,一直以来对几种依赖注册对象的区别和作用不是很了解,今日一探究竟. dependen ...