Luogu P4180 【模板】严格次小生成树[BJWC2010]
题意
题目描述
小\(C\)最近学了很多最小生成树的算法,\(Prim\)算法、\(Kurskal\)算法、消圈算法等等。正当小\(C\)洋洋得意之时,小\(P\)又来泼小\(C\)冷水了。小\(P\)说,让小\(C\)求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说:如果最小生成树选择的边集是\(E_M\),严格次小生成树选择的边集是\(E_S\),那么需要满足:(\(value(e)\)表示边\(e\)的权值)\(\sum_{e\in E_M}value(e)<\sum_{e\in E_S}value(e)\)
这下小\(C\)蒙了,他找到了你,希望你帮他解决这个问题。
输入输出格式
输入格式:
第一行包含两个整数\(N\)和\(M\),表示无向图的点数与边数。接下来\(M\)行,每行\(3\)个数\(x\ y\ z\)表示,点\(x\)和点\(y\)之间有一条边,边的权值为\(z\)。
输出格式:
包含一行,仅一个数,表示严格次小生成树的边权和。(数据保证必定存在严格次小生成树)
输入输出样例
输入样例#1:
5 6
1 2 1
1 3 2
2 4 3
3 5 4
3 4 3
4 5 6
输出样例#1:
11
说明
数据中无向图无自环;
\(50\%\)的数据\(N\leq 2000,M\leq 3000\);
\(80\%\)的数据\(N≤50 000 M≤100 000\);
\(100\%\)的数据\(N≤100000,M≤300000\),边权值非负且不超过\(10^9\)。
思路
先考虑不严格怎么做。先建出最小生成树,然后对每一条不在树上的边进行考虑:加入这条边之后,树上就会多出来一个环,我们把环上最长的一条边删除,就可以得到另一棵生成树。这样产生的生成树里最小的,就是非严格次小生成树了。
得到环上最长的一条边,只需要在原树上求新加边的两顶点之间的\(LCA\),顺便查询最长边就好了。
之所以不是严格的,是因为加入一条边之后删除的边可能与加入的边的边权相同。这样的话,我们就在预处理倍增记录两点最长边的同时记录两点严格次长边,把它去掉,再加入新边,这样就能求得严格次小生成树了。
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<LL,LL> PLL;
const LL MAXN=1e5+5,MAXM=3e5+5;
LL n,m,ans=LLONG_MAX,sum,dad[MAXN],dep[MAXN];
LL cnt,top[MAXN],to[MAXM<<1],len[MAXM<<1],nex[MAXM<<1];
LL fa[MAXN][20],mx1[MAXN][20],mx2[MAXN][20];
struct Edge
{
LL u,v,d;
bool use;
bool operator < (const Edge &sjf) const {return d<sjf.d;}
}edge[MAXM];
LL read()
{
LL re=0;char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) re=(re<<3)+(re<<1)+ch-'0',ch=getchar();
return re;
}
void add_edge(LL x,LL y,LL z)
{
to[++cnt]=y,len[cnt]=z,nex[cnt]=top[x],top[x]=cnt;
to[++cnt]=x,len[cnt]=z,nex[cnt]=top[y],top[y]=cnt;
}
LL fd(LL x)
{
LL r=x;
while(r!=dad[r]) r=dad[r];
LL i=x,j;
while(i!=r) j=dad[i],dad[i]=r,i=j;
return r;
}
void Kruskal()
{
for(LL i=1;i<=n;i++) dad[i]=i;
for(LL i=0;i<m;i++)
{
LL fu=fd(edge[i].u),fv=fd(edge[i].v);
if(fu!=fv) dad[fu]=fv,edge[i].use=true,sum+=edge[i].d,add_edge(edge[i].u,edge[i].v,edge[i].d);
}
}
void dfs(LL now)
{
for(LL i=1;i<=18;i++)
{
fa[now][i]=fa[fa[now][i-1]][i-1];
mx1[now][i]=max(mx1[now][i-1],mx1[fa[now][i-1]][i-1]);
if(mx1[now][i-1]>mx1[fa[now][i-1]][i-1]) mx2[now][i]=max(mx2[now][i-1],mx1[fa[now][i-1]][i-1]);
else if(mx1[now][i-1]<mx1[fa[now][i-1]][i-1]) mx2[now][i]=max(mx1[now][i-1],mx2[fa[now][i-1]][i-1]);
else if(mx1[now][i-1]==mx1[fa[now][i-1]][i-1]) mx2[now][i]=max(mx2[now][i-1],mx2[fa[now][i-1]][i-1]);
}
for(LL i=top[now];i;i=nex[i])
{
if(to[i]==fa[now][0]) continue;
fa[to[i]][0]=now,mx1[to[i]][0]=len[i],dep[to[i]]=dep[now]+1;
dfs(to[i]);
}
}
PLL LCA(LL x,LL y)
{
PLL re;re.first=re.second=0;
if(dep[x]<dep[y]) swap(x,y);
for(LL i=18;i>=0;i--)
if(dep[fa[x][i]]>=dep[y])
{
if(mx1[x][i]>re.first) re.second=re.first,re.first=mx1[x][i];
else if(mx1[x][i]>re.second) re.second=mx1[x][i];
else if(mx2[x][i]>re.second) re.second=mx2[x][i];
x=fa[x][i];
}
if(x==y) return re;
for(LL i=18;i>=0;i--)
if(fa[x][i]!=fa[y][i])
{
if(mx1[x][i]>re.first) re.second=re.first,re.first=mx1[x][i];
else if(mx1[x][i]>re.second) re.second=mx1[x][i];
else if(mx2[x][i]>re.second) re.second=mx2[x][i];
x=fa[x][i];
if(mx1[y][i]>re.first) re.second=re.first,re.first=mx1[y][i];
else if(mx1[y][i]>re.second) re.second=mx1[y][i];
else if(mx2[y][i]>re.second) re.second=mx2[y][i];
y=fa[y][i];
}
if(mx1[x][0]>re.first) re.second=re.first,re.first=mx1[x][0];
else if(mx1[x][0]>re.second) re.second=mx1[x][0];
else if(mx2[x][0]>re.second) re.second=mx2[x][0];
x=fa[x][0];
if(mx1[y][0]>re.first) re.second=re.first,re.first=mx1[y][0];
else if(mx1[y][0]>re.second) re.second=mx1[y][0];
else if(mx2[y][0]>re.second) re.second=mx2[y][0];
y=fa[y][0];
return re;
}
int main()
{
n=read(),m=read();
for(LL i=0;i<m;i++) edge[i].u=read(),edge[i].v=read(),edge[i].d=read();
sort(edge,edge+m);
Kruskal();
dep[1]=1;
dfs(1);
for(LL i=0;i<m;i++)
{
if(edge[i].use) continue;
PLL hjj=LCA(edge[i].u,edge[i].v);
if(edge[i].d!=hjj.first) ans=min(ans,sum-hjj.first+edge[i].d);
else if(hjj.second) ans=min(ans,sum-hjj.second+edge[i].d);
}
printf("%lld",ans);
return 0;
}
Luogu P4180 【模板】严格次小生成树[BJWC2010]的更多相关文章
- P4180 【模板】严格次小生成树[BJWC2010]
P4180 [模板]严格次小生成树[BJWC2010] 倍增(LCA)+最小生成树 施工队挖断学校光缆导致断网1天(大雾) 考虑直接枚举不在最小生成树上的边.但是边权可能与最小生成树上的边相等,这样删 ...
- 【洛谷】4180:【模板】严格次小生成树[BJWC2010]【链剖】【线段树维护最大、严格次大值】
P4180 [模板]严格次小生成树[BJWC2010] 题目描述 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等.正当小C洋洋得意之时,小P又来泼小C冷水了.小P说, ...
- 「LuoguP4180」 【模板】严格次小生成树[BJWC2010](倍增 LCA Kruscal
题目描述 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等.正当小C洋洋得意之时,小P又来泼小C冷水了.小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还得 ...
- 【luogu P4180 严格次小生成树[BJWC2010]】 模板
题目链接:https://www.luogu.org/problemnew/show/P4180 这个题卡树剖.记得开O2. 这个题inf要到1e18. 定理:次小生成树和最小生成树差距只有在一条边上 ...
- 洛谷 P4180 【模板】严格次小生成树[BJWC2010]【次小生成树】
严格次小生成树模板 算法流程: 先用克鲁斯卡尔求最小生成树,然后给这个最小生成树树剖一下,维护边权转点权,维护最大值和严格次大值. 然后枚举没有被选入最小生成树的边,在最小生成树上查一下这条边的两端点 ...
- 【洛谷 P4180】【模板】严格次小生成树[BJWC2010](倍增)
题目链接 题意如题. 这题作为我们KS图论的T4,我直接打了个很暴力的暴力,骗了20分.. 当然,我们KS里的数据范围远不及这题. 这题我debug了整整一个晚上还没debug出来,第二天早上眼前一亮 ...
- P4180 严格次小生成树[BJWC2010] Kruskal,倍增
题目链接\(Click\) \(Here\). 题意就是要求一个图的严格次小生成树.以前被题面吓到了没敢做,写了一下发现并不难. 既然要考虑次小我们就先考虑最小.可以感性理解到一定有一种次小生成树,可 ...
- 【【模板】严格次小生成树[BJWC2010]】
树上的路径怎么能没有树剖 显然,次小生成树和最小生成树只在一条边上有差距,于是我们就可以枚举这一条边,将所有边加入最小生成树,之后再来从这些并不是那么小的生成树中找到那个最小的 我们往最小生成树里加入 ...
- 「BJWC2010」模板严格次小生成树
题目描述 小 \(C\) 最近学了很多最小生成树的算法,\(Prim\) 算法.\(Kruskal\) 算法.消圈算法等等.正当小\(C\)洋洋得意之时,小\(P\)又来泼小\(C\)冷水了.小\(P ...
随机推荐
- <Java编程思想>读书笔记(1)-对象导论、一切都是对象
1.面向对象编程:OOP (Object-oriented Programming) 2.Alan Kay 总结的面向对象语言5个基本特性: 1) 万物皆为对象 2) 程序是对象的集合,他们通过发送消 ...
- HSF简单实现记录( 基于Ali-Tomcat 开发)
文章目录 声明 注意 提示: Ali-Tomcat 概述 安装 Ali-Tomcat 和 Pandora 并配置开发环境 安装 Ali-Tomcat 和 Pandora 配置开发环境 配置 Eclip ...
- 关于double的输入输出
double定义的变量输入的时候一定要%lf输入,要是%f输入的话,得到的结果会是0 float输入的时候是%f 但是在输出的时候%lf和%f都可以输出 建议使用double类型时,用%lf输入,%f ...
- 2019 USP Try-outs 练习赛
// 好久没更博客了,最近打了很多场练习赛&校内PK赛,大概自闭忙于补题吧 // 9.26 周四练习赛 A. Kolkhozy 题意 有 n 个数 \(f[i]\) ,有 q 次询问(l, r ...
- 剑指offer——10跳台阶演变
题目描述 一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级.求该青蛙跳上一个n级的台阶总共有多少种跳法. 题解: 纯找规律题: class Solution { public: ...
- iBATIS存储过程
使用iBATIS配置来调用存储过程.为了理解这一章,首先需要了解我们是如何在MySQL中创建一个存储过程. 在继续对本章学习之前,可以通过MySQL存储过程. 我们已经在MySQL下有EMPLOYEE ...
- log4j架构
Log4j API设计为分层结构,其中每一层提供了不同的对象,对象执行不同的任务.这使得设计灵活,根据将来需要来扩展. 有两种类型可用在Log4j的框架对象. 核心对象: 框架的强制对象和框架的使用. ...
- ECMAScript1.4 对象 | 简单数据类型与复杂数据类型 | 内置对象 | 基本包装类型 | String
对象 函数和对象的区别: 函数:封装代码 对象:封装属性和方法 创建对象的方法: 1,对象字面量{} // 模拟创建一只dog var dog = { // 属性 name: 'puppy', age ...
- Read-Write lock 看可以,不过看的时候不能写
当线程“读取”实例的状态时,实例的状态不会改变,只有线程对实例“写入”操作时才会改变.read-write lock 模式将读取和写入分开来处理,在读取数据前获取读锁定,而写入之前,必须获取写锁定. ...
- iOS开发系列-UIImageView的contentMode
typedef NS_ENUM(NSInteger, UIViewContentMode) { UIViewContentModeScaleToFill, UIViewContentModeScale ...