次小生成树Treehttps://www.luogu.org/problemnew/show/P4180

题目描述

小C最近学了很多最小生成树的算法,Prim算法、Kurskal算法、消圈算法等等。正当小C洋洋得意之时,小P又来泼小C冷水了。小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说:如果最小生成树选择的边集是EM,严格次小生成树选择的边集是ES,那么需要满足:(value(e)表示边e的权值)

\[∑e∈EMvalue(e)<∑e∈ESvalue(e)
\]

这下小 C 蒙了,他找到了你,希望你帮他解决这个问题。

输入格式:

第一行包含两个整数N 和M,表示无向图的点数与边数。 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z。

输出格式:

包含一行,仅一个数,表示严格次小生成树的边权和。(数据保证必定存在严格次小生成树)

先Kruscal最小生成树,然后枚举非树边,权值为w,将边的两端点的路径(LCA)上的最长边用w替换,但由于我们求的是严格次小生成树,所以当最长边边权==w时,需要用严格次大边替代,因此用倍增维护LCA上的严格次大值和最大值.

具体见代码注释:

#define LL long long
#include<cstdio>
#include<algorithm>
#include<cstring>
#define RG register
using namespace std;
const int N=1e5+5,M=3e5+5;
inline LL read()
{
RG int x=0,w=1;RG char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*w;
}
inline LL min(LL a,LL b){return a<b?a:b;}
inline LL max(LL a,LL b){return a>b?a:b;}
LL n,m,cnt,num,Cost,Ans=100000000000000;
LL last[N],par[N],dep[N],f[N][25],f1[N][25],f2[N][25];
//f[i][j]表示i节点2^j祖先的序号,f1[i][j]表示从i到f[i][j]路径上的最大边权,f1[i][j]表示严格次大边权.
bool used[M];
struct edge{//邻接表
LL to,next,w;
}e[2*M];
struct edgm{//存边
LL u,v,w;
}e1[M];
void insert(LL u,LL v,LL w)
{
e[++cnt]=(edge){v,last[u],w};last[u]=cnt;
e[++cnt]=(edge){u,last[v],w};last[v]=cnt;
}
bool cmp(edgm a,edgm b){return a.w<b.w;}
LL find(LL x){return x==par[x]?x:par[x]=find(par[x]);}
void Kruskal()
{
for(LL i=1;i<=m;i++)
{
if(num==n-1)break;
LL a=e1[i].u,b=e1[i].v;
int fa=find(a),fb=find(b);
if(fa==fb)continue;
par[fa]=fb;
Cost+=e1[i].w;//最小生成树
num++;
used[i]=1;//标记树中的边
insert(a,b,e1[i].w);
}
}
void dfs(LL now)//处理深度和f[i][0]以及f1[i][0]
{
for(LL i=last[now];i;i=e[i].next)
{
LL v=e[i].to;
if(dep[v])continue;
dep[v]=dep[now]+1;
f[v][0]=now;
f1[v][0]=e[i].w;
f2[v][0]=-100000000000000;//f2[i][0]置为-inf
dfs(v);
}
}
void init()
{
dep[1]=1;
dfs(1);
for(LL j=1;j<=20;j++)//递推过程
for(LL i=1;i<=n;i++)
{
f[i][j]=f[f[i][j-1]][j-1];
f1[i][j]=max(f1[i][j-1],f1[f[i][j-1]][j-1]);
if(f1[i][j-1]==f1[f[i][j-1]][j-1])f2[i][j]=max(f2[i][j-1],f2[f[i][j-1]][j-1]);
else f2[i][j]=max(min(f1[i][j-1],f1[f[i][j-1]][j-1]),max(f2[i][j-1],f2[f[i][j-1]][j-1]));
}
}
LL LCA(LL a,LL b,LL w)
{
LL dwq[200];//将可能的取值放进数组中,排序方便处理
LL ct=0;
memset(dwq,0,sizeof(dwq));
if(dep[b]>dep[a])swap(a,b);
for(LL i=20;i>=0;i--)//倍增
{
if(f[a][i]&&dep[f[a][i]]>=dep[b])
{
dwq[++ct]=f1[a][i];
dwq[++ct]=f2[a][i];
a=f[a][i];
}
}
if(a!=b)
{
for(LL i=20;i>=0;i--)
if(f[a][i]&&f[b][i]&&f[a][i]!=f[b][i])
{
dwq[++ct]=f1[a][i];
dwq[++ct]=f2[a][i];
dwq[++ct]=f1[b][i];
dwq[++ct]=f2[b][i];
a=f[a][i];
b=f[b][i];
}
dwq[++ct]=f1[a][0];
dwq[++ct]=f1[b][0];
dwq[++ct]=f2[a][0];
dwq[++ct]=f2[b][0];
}
sort(dwq+1,dwq+ct+1);
for(LL i=ct;i>=1;i--)if(dwq[i]<w)return dwq[i];
}
int main()
{
n=read();m=read();
for(LL i=1;i<=n;i++)par[i]=i;
for(LL i=1;i<=m;i++)e1[i]=(edgm){read(),read(),read()};
sort(e1+1,e1+m+1,cmp);
Kruskal();
init();
for(LL i=1;i<=m;i++)
{
if(used[i])continue;
LL a=e1[i].u,b=e1[i].v,w=e1[i].w;
Ans=min(Ans,Cost-LCA(a,b,w)+w);//取最小值
}
printf("%lld\n",Ans);
return 0;
}

次小生成树Tree的更多相关文章

  1. BZOJ 1977: [BeiJing2010组队]次小生成树 Tree( MST + 树链剖分 + RMQ )

    做一次MST, 枚举不在最小生成树上的每一条边(u,v), 然后加上这条边, 删掉(u,v)上的最大边(或严格次大边), 更新答案. 树链剖分然后ST维护最大值和严格次大值..倍增也是可以的... - ...

  2. 1977: [BeiJing2010组队]次小生成树 Tree

    1977: [BeiJing2010组队]次小生成树 Tree https://lydsy.com/JudgeOnline/problem.php?id=1977 题意: 求严格次小生成树,即边权和不 ...

  3. 【BZOJ1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+倍增

    [BZOJ1977][BeiJing2010组队]次小生成树 Tree Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C ...

  4. [BeiJing2010组队]次小生成树 Tree

    1977: [BeiJing2010组队]次小生成树 Tree Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 5168  Solved: 1668[S ...

  5. 洛谷P4180 [Beijing2010组队]次小生成树Tree(最小生成树,LCT,主席树,倍增LCA,倍增,树链剖分)

    洛谷题目传送门 %%%TPLY巨佬和ysner巨佬%%% 他们的题解 思路分析 具体思路都在各位巨佬的题解中.这题做法挺多的,我就不对每个都详细讲了,泛泛而谈吧. 大多数算法都要用kruskal把最小 ...

  6. [BeiJing2010组队][BZOJ 1977]次小生成树 Tree

    话说这个[BeiJing2010组队]是个什喵玩意? 这是一道严格次小生成树,而次小生成树的做法是层出不穷的 MATO IS NO.1 的博客里对两种算法都有很好的解释,值得拥有:  (果然除我以外, ...

  7. 【次小生成树】bzoj1977 [BeiJing2010组队]次小生成树 Tree

    Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了.小 P 说,让小 C 求出一 ...

  8. (luogu4180) [Beijing2010组队]次小生成树Tree

    严格次小生成树 首先看看如果不严格我们怎么办. 非严格次小生成树怎么做 由此,我们发现一个结论,求非严格次小生成树,只需要先用kruskal算法求得最小生成树,然后暴力枚举非树边,替换路径最大边即可. ...

  9. [BJOI 2010]次小生成树Tree

    Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了.小 P 说,让小 C 求出一 ...

  10. BZOJ 1977[BeiJing2010组队]次小生成树 Tree - 生成树

    描述: 就是求一个次小生成树的边权和 传送门 题解 我们先构造一个最小生成树, 把树上的边记录下来. 然后再枚举每条非树边(u, v, val),在树上找出u 到v 路径上的最小边$g_0$ 和 严格 ...

随机推荐

  1. rsync数据同步工具的配置

    rsync数据同步工具的配置 1. rsync介绍 1.1.什么是rsync rsync是一款开源的快速的,多功能的,可实现全量及增量的本地或远程数据同步备份的优秀工具.Rsync软件适用于 unix ...

  2. OpenCV入门笔记(三) 图片处理

    OpenCV中提供了非常多处理图片的强大函数,能够对非常多格式的图片 加特效.有点实现Photoshop里的工具的感觉. 以下先介绍一些简单和常见的特效. 二值化(Image Threshold) 參 ...

  3. ubuntu安装rpm格式软件包

    转载自:http://os.51cto.com/art/200708/53942.htm ubuntu的软件包格式是deb,如果要安装rpm的包,则要先用alien把rpm转换成deb.用alien转 ...

  4. Swing基础知识

    1 http://zxc8899.iteye.com/blog/1556094  最基本的组件 2 http://zhangjunhd.blog.51cto.com/113473/128174 布局管 ...

  5. asp.net core mvc视频A:笔记2-3.高级数据绑定

    默认的绑定顺序,如果需要取指定数据源里的数据,需要通过属性控制,比如[FromQuery] 前端 控制器方法 前端 此时并不能得到head中的数据 改造控制器方法,添加[FromHeader]属性 再 ...

  6. 制作rpm包报错问题

    在编译生成rpm包时,报错 ERROR 0001: file '***' contains a standard rpath '/usr/lib64'这是由于代码理由hardcode导致,解决问题有两 ...

  7. HTML5 的四个亮点

    1.XDM  cross-document-messaging  跨文档消息传递. 2.原生拖放功能. 3.新媒体元素 audio.video. 4.历史状态管理.

  8. slam command tool

    cd imu_ws source devel/setup.bash ls -l /dev |grep ttyUSB sudo chmod /dev/ttyUSB0 rosrun imu_pb imu ...

  9. mysql中的for update

    Select…For Update语句的语法与select语句相同,只是在select语句的后面加FOR UPDATE [NOWAIT]子句. 该语句用来锁定特定的行(如果有where子句,就是满足w ...

  10. SpringSecurity学习三----------通过Security标签库简单显示视图

    © 版权声明:本文为博主原创文章,转载请注明出处 1.项目结构 2.pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0& ...