「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出来,第二天早上眼前一亮 ...
随机推荐
- g2o 初始化
typedef g2o::BlockSolver< g2o::BlockSolverTraits<,> > Block; // pose 维度为 6, landmark 维度为 ...
- Android利用reative_layout生成梅花界面
XML代码: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:and ...
- python之脚本参数optparse
import optparse usage = "myprog[ -f <filename>][-s <xyz>] arg1[,arg2..]" opter ...
- jQuery Validate(二)
刚刚试了所谓的新版的用法.千万别问我是多新,因为我也不知道... <!DOCTYPE html> <html> <head> <script src=&quo ...
- Spark源码分析之一:Job提交运行总流程概述
Spark是一个基于内存的分布式计算框架,运行在其上的应用程序,按照Action被划分为一个个Job,而Job提交运行的总流程,大致分为两个阶段: 1.Stage划分与提交 (1)Job按照RDD之间 ...
- js关于变量作为if条件的真假问题
var a = ""; if(a){ ..... }else{ .....} 以下情况会被认为返回false: "" 空的字符串 为 0 的数字 为 null ...
- js new一个函数和直接调用函数的差别
用new和调用一个函数的差别:假设函数返回值是一个值类型(Number.String.Boolen)时,new函数将会返回这个函数的实例对象.而假设这个函数的返回值是一个引用类型(Object.Arr ...
- 【转】android 签名验证防止重打包
网上资料很多,这里只做一个笔记反编译 dex 修改重新打包签名后 apk 的签名信息肯定会改变,所以可以在代码中判断签名信息是否被改变过,如果签名不一致就退出程序,以防止 apk 被重新打包. 1 j ...
- Android重写FragmentTabHost来实现状态保存
近期要做一个类似QQ底部有气泡的功能,试了几个方案不太好.我想非常多开发人员使用TabHost都会知道它不保存状态.每次都要又一次载入布局.为了保存状态,使用RadioGroup来实现.状态是能够保存 ...
- python 基础 4.3 高阶函数下和匿名函数
一 .匿名函数 顾名思议就是没有名字的函数,那为什么要设立匿名函数,他有什么作用呢?lambda 函数就是一种快速定义单行的最小函数,可以用在任何需要函数的地方. 常规版: def fun(x,y ...