【Beijing 2010】 次小生成树
【题目链接】
【算法】
首先,有一个结论 : 一定有一棵严格次小生成树是在最小生成树的基础上去掉一条边,再加上一条边
这个结论的正确性是显然的
我们先用kruskal算法求出最小生成树,然后,枚举不在最小生成树上的边,我们发现若加上这条边,
则形成了一个环,用最小生成树的权值和加上这条边的权值再减去在这个环上且在最小生成树上权值
最大的边即为包括这条边的最小生成树的权值和
那么,树上倍增可以解决这个问题
因为是要求严格最小,所以我们不仅要记录最大值,还要记录次大值
时间复杂度 : O((N+M)log(N))
【代码】
注意使用long long,INF开到10^18!
#include<bits/stdc++.h>
using namespace std;
#define MAXN 100010
#define MAXM 300010
#define MAXLOG 20
const long long INF = 1e18; struct info
{
int x,y;
long long w;
} edge[MAXM];
struct Edge
{
int to;
long long w;
int nxt;
} e[MAXM<<]; int i,n,m,tot;
int fa[MAXN],head[MAXN],dep[MAXN],anc[MAXN][MAXLOG];
long long ans = INF,val;
long long mx[MAXN][MAXLOG],nx[MAXN][MAXLOG];
bool on_mst[MAXM]; inline bool cmp(info a,info b) { return a.w < b.w; }
inline int get_root(int x)
{
if (fa[x] == x) return x;
return fa[x] = get_root(fa[x]);
}
inline void add(int x,int y,int w)
{
tot++;
e[tot] = (Edge){y,w,head[x]};
head[x] = tot;
}
inline void kruskal()
{
int i,sx,sy;
long long x,y,w;
for (i = ; i <= n; i++) fa[i] = i;
for (i = ; i <= m; i++) on_mst[i] = false;
sort(edge+,edge+m+,cmp);
for (i = ; i <= m; i++)
{
x = edge[i].x;
y = edge[i].y;
w = edge[i].w;
sx = get_root(x);
sy = get_root(y);
if (sx != sy)
{
val += w;
fa[sx] = sy;
on_mst[i] = true;
add(x,y,w);
add(y,x,w);
}
}
}
inline void dfs_init(int u)
{
int i,v;
for (i = ; i < MAXLOG; i++)
{
if (dep[u] < ( << i)) break;
anc[u][i] = anc[anc[u][i-]][i-];
mx[u][i] = max(mx[u][i-],mx[anc[u][i-]][i-]);
if (mx[u][i-] == mx[anc[u][i-]][i-]) nx[u][i] = max(nx[u][i-],nx[anc[u][i-]][i-]);
else nx[u][i] = max(min(mx[u][i-],mx[anc[u][i-]][i-]),max(nx[u][i-],nx[anc[u][i-]][i-]));
}
for (i = head[u]; i; i = e[i].nxt)
{
v = e[i].to;
if (anc[u][] != v)
{
dep[v] = dep[u] + ;
anc[v][] = u;
mx[v][] = e[i].w;
dfs_init(v);
}
}
}
inline long long get(int x,int y,long long w)
{
int i,t;
long long ret = ;
if (dep[x] > dep[y]) swap(x,y);
t = dep[y] - dep[x];
for (i = ; i < MAXLOG; i++)
{
if (t & ( << i))
{
if (mx[y][i] == w) ret = max(ret,nx[y][i]);
else ret = max(ret,mx[y][i]);
y = anc[y][i];
}
}
if (x == y) return ret;
for (i = MAXLOG - ; i >= ; i--)
{
if (anc[x][i] != anc[y][i])
{
if (mx[x][i] == w) ret = max(ret,nx[x][i]);
else ret = max(ret,mx[x][i]);
if (mx[y][i] == w) ret = max(ret,nx[y][i]);
else ret = max(ret,mx[y][i]);
x = anc[x][i];
y = anc[y][i];
}
}
if (mx[x][] != w) ret = max(ret,mx[x][]);
if (mx[y][] != w) ret = max(ret,mx[y][]);
return ret;
}
int main()
{ scanf("%d%d",&n,&m);
for (i = ; i <= m; i++) scanf("%lld%lld%lld",&edge[i].x,&edge[i].y,&edge[i].w);
kruskal();
dfs_init();
for (i = ; i <= m; i++)
{
if (!on_mst[i])
ans = min(ans,val+edge[i].w-get(edge[i].x,edge[i].y,edge[i].w));
}
printf("%lld\n",ans); return ;
}
【Beijing 2010】 次小生成树的更多相关文章
- [BJOI 2010]次小生成树Tree
Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了.小 P 说,让小 C 求出一 ...
- [Luogu P4180][BJWC 2010]严格次小生成树
严格次小生成树,关键是“严格”,如果是不严格的其实只需要枚举每条不在最小生成树的边,如果得到边权和大于等于最小生成树的结束就行.原理就是因为Kruskal非常贪心,只要随便改一条边就能得到一个非严格的 ...
- 次小生成树(lca)
题目描述 原题来自:BeiJing 2010 组队赛 给定一张 N 个点 M 条边的无向图,求无向图的严格次小生成树. 设最小生成树的边权之和为 sum,严格次小生成树就是指边权之和大于 sum 的生 ...
- hdu 4081 Qin Shi Huang's National Road System (次小生成树)
Qin Shi Huang's National Road System Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/3 ...
- HDU4081 Qin Shi Huang's National Road System —— 次小生成树变形
题目链接:https://vjudge.net/problem/HDU-4081 Qin Shi Huang's National Road System Time Limit: 2000/1000 ...
- HDU-4081.Qinshihuang'sNationalRoadSystem(次小生成树变种)
Qin Shi Huang's National Road System Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/3 ...
- HDU 4081Qin Shi Huang's National Road System(次小生成树)
题目大意: 有n个城市,秦始皇要修用n-1条路把它们连起来,要求从任一点出发,都可以到达其它的任意点.秦始皇希望这所有n-1条路长度之和最短.然后徐福突然有冒出来,说是他有魔法,可以不用人力.财力就变 ...
- POJ1679 The Unique MST[次小生成树]
The Unique MST Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 28673 Accepted: 10239 ...
- The Unique MST(次小生成树)
Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 22335 Accepted: 7922 Description Give ...
随机推荐
- Python之turtl库-玫瑰花
Python之turtl库-玫瑰花 #!/usr/bin/env python # coding: utf-8 # Python turtle库官方文档:https://docs.python.org ...
- Python之协程函数
Python之协程函数 什么是协程函数:如果一个函数内部yield的使用方法是表达式形式的话,如x=yield,那么该函数成为协程函数. def eater(name): print('%s star ...
- vue-router 根据路由动态添加目录 控制目录权限
<template> <el-row class="el-menu" > <el-menu router :default-active='$rout ...
- 32道常见的Java基础面试题
1. 什么是 Java 虚拟机(JVM)?为什么 Java 被称作是“平台无关的编程语言”? Java 虚拟机是一个可以执行 Java 字节码的虚拟机进程.Java 源文件被编译成能被 Java 虚拟 ...
- Java AOP
AOP 今天我要和大家分享的是 AOP(Aspect-Oriented Programming)这个东西,名字与 OOP 仅差一个字母,其实它是对 OOP 编程方式的一种补充,并非是取而代之.翻译过来 ...
- 7-9 旅游规划(25 分)(Dijkstra最短路径算法)
有了一张自驾旅游路线图,你会知道城市间的高速公路长度.以及该公路要收取的过路费.现在需要你写一个程序,帮助前来咨询的游客找一条出发地和目的地之间的最短路径.如果有若干条路径都是最短的,那么需要输出最便 ...
- ORACLE审计小结
ORACLE审计小结 1.什么是审计 审计(Audit)用于监视用户所执行的数据库操作,并且Oracle会将审计跟踪结果存放到OS文件(默认位置为$ORACLE_BASE/admin/$ORACLE_ ...
- hihoCoder 必须吐槽hihoCoder的一点 (¯Д¯)ノ
代码输入窗口太小,mac下经常误操作:双指滑动浏览器后退 而且输入框不会自动保存,一不小心后退一下,啥都..都没了...码了好久的代码就没了..遇到不止一次了 (  ̄ .  ̄ ) (゜ ロ゜;) ( ̄ ...
- * SPOJ PGCD Primes in GCD Table (需要自己推线性筛函数,好题)
题目大意: 给定n,m,求有多少组(a,b) 0<a<=n , 0<b<=m , 使得gcd(a,b)= p , p是一个素数 这里本来利用枚举一个个素数,然后利用莫比乌斯反演 ...
- csu1364 Interview
对拍了一波才找到的错误,此题我用的是二分答案加倍增查询,实际上query那里我觉得仍然有缺陷,因为每一次我的查找还是在循环找到一个k使得x+2^k <= y,而错的地方也正在此地,一开始没有判断 ...