题面

传送门

题目大意:

给定一个无向连通带权图G,对于每条边(u,v,w)" role="presentation" style="position: relative;">(u,v,w)(u,v,w),求包含这条边的生成树大小的最小值

分析

包含这条边的生成树的大小如何表示呢?

先求出整张图的最小生成树大小tlen,对于每一条边(u,v,w)" role="presentation" style="position: relative;">(u,v,w)(u,v,w),我们最小生成树中去掉树上从u到v的路径上权值最大,最大值为mlen的一条边,再加上w,得到的一定是包含这条边的生成树大小的最小值tlen−mlen+w" role="presentation" style="position: relative;">tlen−mlen+wtlen−mlen+w

最小生成树大小tlen可用kruskal算法在O(mlog2m)" role="presentation" style="position: relative;">O(mlog2m)O(mlog2m)时间内求出

那么问题转化为求mlen,可用树上倍增法求解

树上倍增法的好处是在求LCA的同时可以维护更多的附加信息

在求LCA的过程中设fa[i][j]表示i的2j" role="presentation" style="position: relative;">2j2j辈祖先

可写出公式

fa[i][j]=fa[fa[i][j−1]][j−1]" role="presentation">fa[i][j]=fa[fa[i][j−1]][j−1]fa[i][j]=fa[fa[i][j−1]][j−1]

(即i的2j" role="presentation" style="position: relative;">2j2j辈祖先是i的2j−1" role="presentation" style="position: relative;">2j−12j−1辈祖先的2j−1" role="presentation" style="position: relative;">2j−12j−1辈祖先)

同理可写出最大长度

mlen[i][j]=max(mlen[i][j−1],mlen[mlen[i][j−1]][j−1])" role="presentation">mlen[i][j]=max(mlen[i][j−1],mlen[mlen[i][j−1]][j−1])mlen[i][j]=max(mlen[i][j−1],mlen[mlen[i][j−1]][j−1])

查询时类似LCA的查询即可,详情见代码

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
#define maxn 200005
#define maxm 200005
#define maxlog 32
using namespace std;
int n,m;
inline int qread(){
int x=0,sign=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-') sign=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=x*10+c-'0';
c=getchar();
}
return x*sign;
}
struct edge{
int from;
int to;
int len;
int next;
int index;
edge(){ }
edge(int x,int y,int z,int i){
from=x;
to=y;
len=z;
index=i;
}
friend bool operator <(edge x,edge y){
return x.len<y.len;
}
};
edge G[maxm*2],MST[maxm*2];
int head[maxn];
int size=0;
void add_edge(int u,int v,int w){
size++;
MST[size].from=u;
MST[size].to=v;
MST[size].len=w;
MST[size].next=head[u];
head[u]=size;
}
int fset[maxn];
void set_init(){
for(int i=1;i<=n;i++) fset[i]=i;
}
int find(int x){
if(fset[x]==x) return x;
else{
fset[x]=find(fset[x]);
return fset[x];
}
}
long long kruskal(){
long long ans=0;
sort(G+1,G+1+m);
for(int i=1;i<=m;i++){
int fx=find(G[i].from);
int fy=find(G[i].to);
if(fx!=fy){
add_edge(G[i].from,G[i].to,G[i].len);
add_edge(G[i].to,G[i].from,G[i].len);
fset[fx]=fy;
ans+=G[i].len;
}
}
return ans;
} int deep[maxn],fa[maxn][maxlog];
long long mlen[maxn][maxlog];
int log2n;
void lca_init(){
queue<int>q;
q.push(1);
deep[1]=1; //初始化深度
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=head[x];i;i=MST[i].next){//MST表示最小生成树的边
int y=MST[i].to;
if(deep[y]) continue;
deep[y]=deep[x]+1;
fa[y][0]=x;//fa和mlen的初始值
mlen[y][0]=MST[i].len;
for(int j=1;j<=log2n;j++){//倍增初始化
fa[y][j]=fa[fa[y][j-1]][j-1];
mlen[y][j]=max(mlen[y][j-1],mlen[fa[y][j-1]][j-1]);
}
q.push(y);
}
}
}
long long lca_query(int x,int y){
if(deep[x]>deep[y]) swap(x,y);
long long maxl=0;
for(int i=log2n;i>=0;i--){//先将x和y调整到同一深度
if(deep[fa[y][i]]>=deep[x]){
maxl=max(maxl,mlen[y][i]);//y上升同时更新maxl
y=fa[y][i];
}
}
if(x==y) return maxl;//如果LCA(x,y)=x,直接返回
for(int i=log2n;i>=0;i--){//x,y同时上升,直到差一条边相遇
if(fa[x][i]!=fa[y][i]){
maxl=max(maxl,max(mlen[x][i],mlen[y][i]));
x=fa[x][i];
y=fa[y][i];
}
}
maxl=max(maxl,max(mlen[x][0],mlen[y][0]));//最后再更新一次
return maxl;
}
long long ans[maxm];//便于按输入顺序输出
int main(){
int s,t,r;
n=qread();
m=qread();
for(int i=1;i<=m;i++){
s=qread();
t=qread();
r=qread();
G[i]=edge(s,t,r,i);
}
set_init();
long long tlen=kruskal();
log2n=log2(n)+1;
lca_init();
for(int i=1;i<=m;i++){
ans[G[i].index]=tlen+(long long)G[i].len-(long long)lca_query(G[i].from,G[i].to);//求生成树大小的最小值
}
for(int i=1;i<=m;i++){
printf("%I64d\n",ans[i]);
}
}

Codeforces 609E (Kruskal求最小生成树+树上倍增求LCA)的更多相关文章

  1. 【BZOJ 3551】[ONTAK2010] Peaks加强版 Kruskal重构树+树上倍增+主席树

    这题真刺激...... I.关于Kruskal重构树,我只能开门了,不过补充一下那玩意还是一棵满二叉树.(看一下内容之前请先进门坐一坐) II.原来只是用树上倍增求Lca,但其实树上倍增是一种方法,L ...

  2. 树上倍增求LCA及例题

    先瞎扯几句 树上倍增的经典应用是求两个节点的LCA 当然它的作用不仅限于求LCA,还可以维护节点的很多信息 求LCA的方法除了倍增之外,还有树链剖分.离线tarjan ,这两种日后再讲(众人:其实是你 ...

  3. [学习笔记] 树上倍增求LCA

    倍增这种东西,听起来挺高级,其实功能还没有线段树强大.线段树支持修改.查询,而倍增却不能支持修改,但是代码比线段树简单得多,而且当倍增这种思想被应用到树上时,它的价值就跟坐火箭一样,噌噌噌地往上涨. ...

  4. 树上倍增求LCA(最近公共祖先)

    前几天做faebdc学长出的模拟题,第三题最后要倍增来优化,在学长的讲解下,尝试的学习和编了一下倍增求LCA(我能说我其他方法也大会吗?..) 倍增求LCA: father[i][j]表示节点i往上跳 ...

  5. [算法]树上倍增求LCA

    LCA指的是最近公共祖先(Least Common Ancestors),如下图所示: 4和5的LCA就是2 那怎么求呢?最粗暴的方法就是先dfs一次,处理出每个点的深度 然后把深度更深的那一个点(4 ...

  6. 树上倍增求LCA详解

    LCA(least common ancestors)最近公共祖先 指的就是对于一棵有根树,若结点z既是x的祖先,也是y的祖先(不要告诉我你不知道什么是祖先),那么z就是结点x和y的最近公共祖先. 定 ...

  7. BZOJ 4242 水壶(BFS建图+最小生成树+树上倍增)

    题意 JOI君所居住的IOI市以一年四季都十分炎热著称. IOI市是一个被分成纵H*横W块区域的长方形,每个区域都是建筑物.原野.墙壁之一.建筑物的区域有P个,编号为1...P. JOI君只能进入建筑 ...

  8. [luogu3379]最近公共祖先(树上倍增求LCA)

    题意:求最近公共祖先. 解题关键:三种方法,1.st表 2.倍增法 3.tarjan 此次使用倍增模板(最好采用第一种,第二种纯粹是习惯) #include<cstdio> #includ ...

  9. CF 519E(树上倍增求lca)

    传送门:A and B and Lecture Rooms 题意:给定一棵树,每次询问到达点u,v距离相等的点有多少个. 分析:按情况考虑: 1.abs(deep[u]-deep[v])%2==1时, ...

随机推荐

  1. 32.密码学知识-SSL/TLS-9——2019年12月19日

    9. SSL/TLS "SSL/TLS --- 为了更安全的通信" 本章中我们将学习SSL/TLS的相关知识. SSL/TLS是世界上应用最广泛的密码通信方法.比如说,当在网上商城 ...

  2. Java动手动脑02

    一.平方数静方法: public class SquareInt { public static void main(String[] args) { int result; for (int x = ...

  3. vue2.0发布

    http://blog.csdn.net/xuefeiliuyuxiu/article/details/78970815

  4. kali安装docker以及配置阿里云镜像加速

    1.需求 最近需要用到docker比较多,遂安装使用下,第一次用docker搭建测试环境,不得不说,docker真香.期间遇到了比较多奇奇怪怪的问题,网上的教程也比较多比较乱,遂记录一下. 2.安装d ...

  5. React Native 之项目的启动

    运行项目有两种方法 1. 到根目录,执行 react-native run-ios 命令 会开启一个本地服务,加载jsbundle文件,然后是去index.js文件 import {AppRegist ...

  6. codevs 3060 抓住那头奶牛 x

    3060 抓住那头奶牛 USACO  时间限制: 1 s  空间限制: 16000 KB  题目等级 : 黄金 Gold   题目描述 Description 农夫约翰被告知一头逃跑奶牛的位置,想要立 ...

  7. [USACO17JAN]Promotion Counting 题解

    前言 巨佬说:要有线段树,结果蒟蒻打了一棵树状数组... 想想啊,奶牛都开公司当老板了,我还在这里码代码,太失败了. 话说奶牛开个公司老板不应该是FarmerJohn吗? 题解 刚看到这道题的时候竟然 ...

  8. 果蝇优化算法(FOA)

    果蝇优化算法(FOA) 果蝇优化算法(Fruit Fly Optimization Algorithm, FOA)是基于果蝇觅食行为的仿生学原理而提出的一种新兴群体智能优化算法. 果蝇优化算法(FOA ...

  9. JS FormData 文件异步提交

    html <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3 ...

  10. 6.25考试整理:江城唱晚&&不老梦&&棠梨煎雪——题解

    按照旧例,先安利一下主要作者:一扶苏一 以及扶苏一直挂念的——银临姐姐:银临_百度百科 (滑稽) 好哒,现在步入正题: 先看第一题: 题解: 在NOIP范围内,看到“求方案数”,就说明这个题是一个计数 ...