「LuoguP4180」 【模板】严格次小生成树[BJWC2010](倍增 LCA Kruscal
题目描述
小C最近学了很多最小生成树的算法,Prim算法、Kurskal算法、消圈算法等等。正当小C洋洋得意之时,小P又来泼小C冷水了。小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说:如果最小生成树选择的边集是EM,严格次小生成树选择的边集是ES,那么需要满足:(value(e)表示边e的权值) \sum_{e \in E_M}value(e)<\sum_{e \in E_S}value(e)∑e∈EMvalue(e)<∑e∈ESvalue(e)
这下小 C 蒙了,他找到了你,希望你帮他解决这个问题。
输入输出格式
输入格式:
第一行包含两个整数N 和M,表示无向图的点数与边数。 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z。
输出格式:
包含一行,仅一个数,表示严格次小生成树的边权和。(数据保证必定存在严格次小生成树)
输入输出样例
说明
数据中无向图无自环; 50% 的数据N≤2 000 M≤3 000; 80% 的数据N≤50 000 M≤100 000; 100% 的数据N≤100 000 M≤300 000 ,边权值非负且不超过 10^9 。
题解
话说这个还没有经典到当模板吧qwq
先做一个最小生成树,图被分成树边和非树边。
在这个树上随便找个点当根,预处理好倍增的东西(包括往上$2^j$步的祖先编号,往祖先走的这条路上最长的边,这条路上第二长的边
然后把每条非树边跑一遍,设两点为$u,v$。
可以想到,从$u$到$v$的这条树上路径中找一条最大但小于这条非树边的边替换,这样的结果是严格次小生成树的一个备选结果。
所以就一边求lca一边跟那一段的最长边和第二长边对比啊什么的。
//记录第二长边主要是防止最长边和这条非树边一样长
作为紫题非常好写,非常不容易错。(毕竟只是倍增lca和Kruscal揉到一起的一个东西,元件都不难写qwq
但确实很长就是了qwq
/*
qwerta
P4180 【模板】严格次小生成树[BJWC2010] Accepted
100
代码 C++,2.72KB
提交时间 2018-10-31 19:50:25
耗时/内存 1812ms, 35376KB
*/
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
inline int read()
{
char ch=getchar();
int x=;
while(!isdigit(ch))ch=getchar();
while(isdigit(ch)){x=x*+ch-'';ch=getchar();}
return x;
}
const int MAXN=1e5+,MAXM=3e5+;
struct emm{
int x,y,l,tag;
}b[MAXM];//用来存原图,tag表示是否为树边
bool cmp(emm qaq,emm qwq){
return qaq.l<qwq.l;
}//用来最小生成树
int fa[MAXN];
int fifa(int x)
{
if(fa[x]==x)return x;
return fa[x]=fifa(fa[x]);
}
struct ahh{
int e,f,l;
}a[*MAXN];//用来存树
int h[MAXN];
int tot=;
void con(int x,int y,int l)//连树边
{
a[++tot].f=h[x];
h[x]=tot;
a[tot].e=y;
a[tot].l=l;
a[++tot].f=h[y];
h[y]=tot;
a[tot].e=x;
a[tot].l=l;
return;
}
int w[MAXN],d[MAXN];//w把边权记在深度较深的点上,d为深度
void dfs(int x)//dfs建树
{
for(int i=h[x];i;i=a[i].f)
if(!d[a[i].e])
{
fa[a[i].e]=x;
d[a[i].e]=d[x]+;
w[a[i].e]=a[i].l;
dfs(a[i].e);
}
return;
}
int f[MAXN][];//往上2^j步的祖先
int mac[MAXN][];//往上2^j步途中最长的边长
int macc[MAXN][];//往上2^j步途中严格第二长的边长
int zz[];//辅助数组
bool cmpp(int qaq,int qwq){
return qaq>qwq;
}//用来给zz排序
int main()
{
//freopen("a.in","r",stdin);
int n=read(),m=read();
for(int i=;i<=m;++i)
{
b[i].x=read(),b[i].y=read(),b[i].l=read();
}
//做个最小生成树↓
sort(b+,b+m+,cmp);
for(int i=;i<=n;++i)
fa[i]=i;
int k=n-,j=;
long long sum=;
while(k)
{
j++;
int u=fifa(b[j].x),v=fifa(b[j].y);
if(u!=v)
{
fa[u]=v;
//cout<<b[j].x<<" "<<b[j].y<<" "<<b[j].l<<endl;
b[j].tag=;
sum+=b[j].l;//记下树边权值和
con(b[j].x,b[j].y,b[j].l);//把两点连起来
k--;
}
}
//dfs建树↓
memset(fa,,sizeof(fa));
int s=min(n,);
d[s]=;
dfs(s);
//倍增↓
for(int i=;i<=n;++i)
{
// /cout<<i<<" "<<fa[i]<<endl;
f[i][]=fa[i];
mac[i][]=w[i];
}
for(int j=;j<=;++j)
for(int i=;i+(<<j)-<=n;++i)
{
f[i][j]=f[f[i][j-]][j-];
zz[]=mac[i][j-],zz[]=macc[i][j-];
zz[]=mac[f[i][j-]][j-],zz[]=macc[f[i][j-]][j-];
//这里用zz只是懒得写if
sort(zz+,zz+,cmpp);//从大到小sort一下
unique(zz+,zz+);//因为要严格第二大所以unique一下
mac[i][j]=zz[];
macc[i][j]=zz[];
}
long long ans=1e14+;
for(int i=;i<=m;++i)
if(!b[i].tag)//循环每条非树边
{
int u=b[i].x,v=b[i].y;
//倍增求lca
if(d[u]<d[v])swap(u,v);
for(int j=;j>=;--j)
if(d[u]-d[v]>=(<<j))
{
if(b[i].l>mac[u][j])//如果非树边比最长边长
ans=min(ans,sum-mac[u][j]+b[i].l);//这两条替换是一种可能方案
else if(b[i].l==mac[u][j])//否则如果非树边跟最长边一样长
ans=min(ans,sum-macc[u][j]+b[i].l);//把这条边跟第二长边替换是一种可能方案
u=f[u][j];//记得往上跳
}
if(u==v)continue;
for(int j=;j>=;--j)
if(f[u][j]!=f[v][j])
{
if(b[i].l>mac[u][j])
ans=min(ans,sum-mac[u][j]+b[i].l);
else if(b[i].l==mac[u][j])
ans=min(ans,sum-macc[u][j]+b[i].l);
u=f[u][j];
if(b[i].l>mac[v][j])
ans=min(ans,sum-mac[v][j]+b[i].l);
else if(b[i].l==mac[v][j])
ans=min(ans,sum-macc[v][j]+b[i].l);
v=f[v][j];
}
if(b[i].l>w[u])
ans=min(ans,sum-w[u]+b[i].l);
if(b[i].l>w[v])
ans=min(ans,sum-w[v]+b[i].l);
}
cout<<ans<<endl;//输出撒花
return ;
}
「LuoguP4180」 【模板】严格次小生成树[BJWC2010](倍增 LCA Kruscal的更多相关文章
- 「BJWC2010」模板严格次小生成树
题目描述 小 \(C\) 最近学了很多最小生成树的算法,\(Prim\) 算法.\(Kruskal\) 算法.消圈算法等等.正当小\(C\)洋洋得意之时,小\(P\)又来泼小\(C\)冷水了.小\(P ...
- P4180 【模板】严格次小生成树[BJWC2010]
P4180 [模板]严格次小生成树[BJWC2010] 倍增(LCA)+最小生成树 施工队挖断学校光缆导致断网1天(大雾) 考虑直接枚举不在最小生成树上的边.但是边权可能与最小生成树上的边相等,这样删 ...
- 【洛谷】4180:【模板】严格次小生成树[BJWC2010]【链剖】【线段树维护最大、严格次大值】
P4180 [模板]严格次小生成树[BJWC2010] 题目描述 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等.正当小C洋洋得意之时,小P又来泼小C冷水了.小P说, ...
- Luogu P4180 【模板】严格次小生成树[BJWC2010]
P4180 [模板]严格次小生成树[BJWC2010] 题意 题目描述 小\(C\)最近学了很多最小生成树的算法,\(Prim\)算法.\(Kurskal\)算法.消圈算法等等.正当小\(C\)洋洋得 ...
- POJ 1679 The Unique MST:次小生成树【倍增】
题目链接:http://poj.org/problem?id=1679 题意: 给你一个图,问你这个图的最小生成树是否唯一. 题解: 求这个图的最小生成树和次小生成树.如果相等,则说明不唯一. 次小生 ...
- 洛谷 P4180 【模板】严格次小生成树[BJWC2010]【次小生成树】
严格次小生成树模板 算法流程: 先用克鲁斯卡尔求最小生成树,然后给这个最小生成树树剖一下,维护边权转点权,维护最大值和严格次大值. 然后枚举没有被选入最小生成树的边,在最小生成树上查一下这条边的两端点 ...
- 【【模板】严格次小生成树[BJWC2010]】
树上的路径怎么能没有树剖 显然,次小生成树和最小生成树只在一条边上有差距,于是我们就可以枚举这一条边,将所有边加入最小生成树,之后再来从这些并不是那么小的生成树中找到那个最小的 我们往最小生成树里加入 ...
- 【luogu P4180 严格次小生成树[BJWC2010]】 模板
题目链接:https://www.luogu.org/problemnew/show/P4180 这个题卡树剖.记得开O2. 这个题inf要到1e18. 定理:次小生成树和最小生成树差距只有在一条边上 ...
- 【洛谷 P4180】【模板】严格次小生成树[BJWC2010](倍增)
题目链接 题意如题. 这题作为我们KS图论的T4,我直接打了个很暴力的暴力,骗了20分.. 当然,我们KS里的数据范围远不及这题. 这题我debug了整整一个晚上还没debug出来,第二天早上眼前一亮 ...
随机推荐
- Spring IOC源码分析之-刷新前的准备工作
目录 ClassPathXmlApplicationContext的注册方式 加载父子容器 配置路径解析 容器刷新 刷新容器之刷新预处理 ClassPathXmlApplicationContext的 ...
- session 的工作原理以及使用细节和url编码
/**********************************************模拟页面************************************************* ...
- easyUI中 datagrid 一列字比较多时,出现省略符号
当数据比较多为,出现省略符号 <style type="text/css"> .datagrid-cell, .datagrid-cell-gro ...
- 01 http协议概念及工作流程
一:HTTP协议 重要性: 无论是以后用webserverice ,还是用rest做大型架构,都离不开对HTTP协议的认识. 甚至可以简化的说: webservice = http协议+XML Res ...
- python MySQLdb Windows下安装教程及问题解决方法(python2.7)
使用python访问mysql,需要一系列安装 linux下MySQLdb安装见 Python MySQLdb在Linux下的快速安装http://www.jb51.net/article/6574 ...
- Android中List循环遍历性能对照
在android开发中仅仅要是列表式风格界面我们差点儿都须要用到List来存放数据,在数量非常少的List的话差点儿不论什么一种循环遍历方式总体性能都无区别.可是当我们遇到数据量稍大的时候有必要考虑用 ...
- My97datepicker日期控件
转自:http://www.my97.net/dp/demo/index.htm 非常不错的一篇文章,介绍的很详细.感兴趣的朋友可以好好研究一下. 网上资源很多的,可以下一个来使用. 先说一下整个文件 ...
- css多余字符显示省略号
width:300px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; ;
- Flask:web表单
客户端发送的所有通过POST发出的请求信息都可以通过request.form获取.但是如果我们要生成表单的HTML代码和验证提交的表单数据那么就需要采用另外的方法.Flask-WTF扩展可以把处理we ...
- 如何在ubuntun中安装pycharm并将图标显示在桌面上
安装pycharm首先要安装jdk. 可以通过java -V来查看是否安装了jdk.安装jdk的方法如下: 1 首先在oracle网站下载jdk,现在jdk是1.8的. 2 新建一个/usr/lib/ ...