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, ...
随机推荐
- kubernetes 持久化部署lamp类型网站
1.构建mariadb的镜像 cat Dockerfile FROM mariadb:latest ADD twocloud_kk.sql /docker-entrypoint-initdb.d #C ...
- 源码篇:Python 实战案例----银行系统
import time import random import pickle import os class Card(object): def __init__(self, cardId, car ...
- 为什么建议php字符串使用单引号而不是双引号
不少php提升效率的tip,都有提到字符串使用单引号,这是为什么呢? 因为在单引号中,php直接认为它里头包含的就是个字符串.而双引号时,php会检测里头是否包含变量.这样如果是纯粹的字符串的话,双引 ...
- 通过jQuery Ajax使用FormData对象上传文件 (转载)
XMLHttpRequest Level 2 添加了一个新的接口——FormData.与普通的 Ajax 相比,使用 FormData 的最大优点就是我们可以异步上传二进制文件.jQuery 2.0+ ...
- LOJ #6062. 「2017 山东一轮集训 Day2」Pair
这是Lowest JN dalao昨天上课讲的一道神题其实是水题啦 题意很简单,我们也很容易建模转化出一个奇怪的东西 首先我们对b进行sort,然后我们就可以通过二分来判断出这个数可以和哪些数配对 然 ...
- 阿里云Centos搭建jdk环境
当我们开始了自己的开发,那么云服务器是一定少不了的,当然也有很多同学只是在本地做开发研究. 这里记录一下我自己在阿里云上搭建环境的过程. 趁着优惠的时候,我在阿里云上购买了ECS云服务器,并且搭载了C ...
- Jmeter-使用Ultimate Thread Group插件来设置负载场景
前言: Jmeter插件相关请移步:https://www.jianshu.com/p/130c7fddeddf 自定义线程组:jp@gc - Ultimate Thread Group,功能强大,可 ...
- 剑指offer:二叉树中和为某一值的路径
本来这只是一个普通的算法题,但是当初自己OJ上提交时,总是提交失败,而我自己认定程序逻辑没有任何问题.然后开始就在本机上调试,结果发现这是由于Python的对象机制而引发的.所以先把问题算法题贴出来, ...
- openpyxl 实现excel字母列号与数字列号之间的转换
https://www.cnblogs.com/apple2016/p/9686433.html
- 【CV】ICCV2015_Unsupervised Learning of Spatiotemporally Coherent Metrics
Unsupervised Learning of Spatiotemporally Coherent Metrics Note here: it's a learning note on the to ...