【BZOJ1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+倍增
【BZOJ1977】[BeiJing2010组队]次小生成树 Tree
Description
小 C 最近学了很多最小生成树的算法,Prim 算法、Kurskal 算法、消圈算法等等。 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了。小 P 说,让小 C 求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说: 如果最小生成树选择的边集是 EM,严格次小生成树选择的边集是 ES,那么需要满足:(value(e) 表示边 e的权值)
这下小 C 蒙了,他找到了你,希望你帮他解决这个问题。
Input
第一行包含两个整数N 和M,表示无向图的点数与边数。 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z。
Output
包含一行,仅一个数,表示严格次小生成树的边权和。(数据保证必定存在严格次小生成树)
Sample Input
1 2 1
1 3 2
2 4 3
3 5 4
3 4 3
4 5 6
Sample Output
HINT
数据中无向图无自环; 50% 的数据N≤2 000 M≤3 000; 80% 的数据N≤50 000 M≤100 000; 100% 的数据N≤100 000 M≤300 000 ,边权值非负且不超过 10^9 。
题解:结论!次小生成树一定可以由 最小生成树+一条非树边-这条非树边覆盖的一条边 得到。证明方法。。。假设我们要加入两条边,先加一条边a使总权值变大,再加一条边b使权值变小。那么b所替换掉的边一定在a形成的环上,因为a是非树边,所以a的权值比环上的所有边都大,所以b替换掉的边权值一定不会大于a,所以我们就白加入a这条边了。(奇怪的证明)
所以我们要替换那条边呢?如果它所覆盖的边的最大值=这条非树边的权值,则替换它所覆盖的边的次大值;如果不相等,则直接替换最大值。这就需要我们求出一条路径上的权值最大值和次大值,可以用树剖,当然我觉得倍增更优美一点~
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=100010;
int n,m,cnt;
ll ans,sum;
struct edge
{
int a,b,val,used;
}p[maxn*3];
struct node
{
int x,y;
node() {x=0,y=-1;}
node(int _){x=_,y=0;}
node operator + (const node &a)const
{
node b;
if(x<a.x) b.x=a.x,b.y=max(x,a.y);
if(x>a.x) b.x=x,b.y=max(y,a.x);
if(x==a.x) b.x=x,b.y=max(y,a.y);
return b;
}
}s[19][maxn];
int to[maxn<<1],next[maxn<<1],head[maxn],val[maxn<<1],fa[19][maxn],dep[maxn],Log[maxn],f[maxn];
bool cmp(const edge &a,const edge &b)
{
return a.val<b.val;
}
int find(int x)
{
return (f[x]==x)?x:f[x]=find(f[x]);
}
inline void add(int a,int b,int c)
{
to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
}
inline node ask(int a,int b)
{
if(dep[a]<dep[b]) swap(a,b);
node ret;
for(int i=Log[dep[a]-dep[b]];i>=0;i--) if(dep[fa[i][a]]>=dep[b]) ret=ret+s[i][a],a=fa[i][a];
if(a==b) return ret;
for(int i=Log[dep[a]];i>=0;i--) if(fa[i][a]!=fa[i][b]) ret=ret+s[i][a]+s[i][b],a=fa[i][a],b=fa[i][b];
return ret+s[0][a]+s[0][b];
}
void dfs(int x)
{
for(int i=head[x];i!=-1;i=next[i]) if(to[i]!=fa[0][x])
fa[0][to[i]]=x,dep[to[i]]=dep[x]+1,s[0][to[i]]=node(val[i]),dfs(to[i]);
}
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}
int main()
{
n=rd(),m=rd();
int i,j,a,b;
for(i=1;i<=m;i++) p[i].a=rd(),p[i].b=rd(),p[i].val=rd();
sort(p+1,p+m+1,cmp);
for(i=1;i<=n;i++) f[i]=i;
memset(head,-1,sizeof(head));
for(i=1;i<=m;i++)
{
a=find(p[i].a),b=find(p[i].b);
if(a!=b)
{
add(p[i].a,p[i].b,p[i].val),add(p[i].b,p[i].a,p[i].val),f[a]=b,p[i].used=1,sum+=p[i].val;
if(cnt==(n-1)<<1) break;
}
}
dep[1]=1,dfs(1);
for(i=2;i<=n;i++) Log[i]=Log[i>>1]+1;
for(j=1;(1<<j)<=n;j++) for(i=1;i<=n;i++) fa[j][i]=fa[j-1][fa[j-1][i]],s[j][i]=s[j-1][i]+s[j-1][fa[j-1][i]];
ans=1ll<<60;
for(i=1;i<=m;i++) if(!p[i].used)
{
node tmp=ask(p[i].a,p[i].b);
if(tmp.x!=p[i].val&&tmp.x>0) ans=min(ans,sum+p[i].val-tmp.x);
if(tmp.y>0) ans=min(ans,sum+p[i].val-tmp.y);
}
printf("%lld",ans);
return 0;
}
【BZOJ1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+倍增的更多相关文章
- [bzoj1977][BeiJing2010组队]次小生成树 Tree——树上倍增+lca
Brief Description 求一个无向图的严格次小生成树. Algorithm Design 考察最小生成树的生成过程.对于一个非树边而言,如果我们使用这一条非树边去替换原MST的路径上的最大 ...
- 【bzoj1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+权值线段树合并
题目描述 求一张图的严格次小生成树的边权和,保证存在. 输入 第一行包含两个整数N 和M,表示无向图的点数与边数. 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z ...
- 【次小生成树】bzoj1977 [BeiJing2010组队]次小生成树 Tree
Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了.小 P 说,让小 C 求出一 ...
- bzoj1977 [BeiJing2010组队]次小生成树 Tree
和倍增法求lca差不多,维护每个点往上跳2^i步能到达的点,以及之间的边的最大值和次大值,先求出最小生成树,对于每个非树边枚举其端点在树上的路径的最大值,如果最大值和非树边权值一样则找次大值,然后维护 ...
- bzoj1977 [BeiJing2010组队]次小生成树 Tree——严格次小生成树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1977 因为严格,所以要记录到 LCA 的一个次小值: 很快写好,然后改掉一堆错误后终于过了样 ...
- BZOJ 1977: [BeiJing2010组队]次小生成树 Tree( MST + 树链剖分 + RMQ )
做一次MST, 枚举不在最小生成树上的每一条边(u,v), 然后加上这条边, 删掉(u,v)上的最大边(或严格次大边), 更新答案. 树链剖分然后ST维护最大值和严格次大值..倍增也是可以的... - ...
- 1977: [BeiJing2010组队]次小生成树 Tree
1977: [BeiJing2010组队]次小生成树 Tree https://lydsy.com/JudgeOnline/problem.php?id=1977 题意: 求严格次小生成树,即边权和不 ...
- [BeiJing2010组队]次小生成树 Tree
1977: [BeiJing2010组队]次小生成树 Tree Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 5168 Solved: 1668[S ...
- 洛谷P4180 [Beijing2010组队]次小生成树Tree(最小生成树,LCT,主席树,倍增LCA,倍增,树链剖分)
洛谷题目传送门 %%%TPLY巨佬和ysner巨佬%%% 他们的题解 思路分析 具体思路都在各位巨佬的题解中.这题做法挺多的,我就不对每个都详细讲了,泛泛而谈吧. 大多数算法都要用kruskal把最小 ...
随机推荐
- Json杂谈系列------(一)初始json
1. JSON 是什么 JSON,全称是 JavaScript Object Notation,即 JavaScript 对象标记法.这是一种轻量级(Light-Weight).基于文本的(Text- ...
- 微信团队分享:iOS版微信是如何防止特殊字符导致的炸群、APP崩溃的?
本文来自微信开发团队yanyang的技术分享. 1.引言 相信大家都遇到过一段特殊文本可以让iOS设备所有app闪退的经历.前段时间大年初一,又出现某个印度语字符引起iOS11系统奔溃,所幸iOS版微 ...
- MyISAM的key_buffer_size和InnoDB的innodb_buffer_pool_size
一.MyISAM的key_buffer_size MyISAM的索引方式是非聚集索引,主索引和其他索引没有本质区别,在data域都是存储了具体记录行的地址.key_buffer_size规定了系统将多 ...
- dubbo笔记
使用Maven打包依赖项,启动时从本地jar中读取dubbo.xsd 最近项目用到dubbo,打包启动时报错 Failed to read schema document from http://co ...
- cookie 与 session 的差别、联系
1.存放位置: Session 存放在server端. Cookie 存放在client: 2.保存形式: Session保存在server的内存中(在server端设置超时时间,与浏览器设置无关): ...
- Android Studio+SVN配置生成apk文件
Android Studio 是谷歌推出一个Android集成开发工具,基于IntelliJ IDEA. 类似 Eclipse ADT,Android Studio 提供了集成的 Android 开发 ...
- unity,实现屏幕后处理的两种方法
方法一: Main Camera的Target Texture保持为None.挂一个Blit脚本,在其中的OnRenderImage中调用Graphics.Blit(sourceTexture,des ...
- DevStore开发人员服务有奖征文:小谈新浪微博开放平台
DevStore开发人员服务有奖征文:小谈新浪微博开放平台 笔者接入新浪微博开发平台也有一段时间了,对整个平台的接入也算比較熟悉,新浪提供了统一的API接口,能够让开发人员更方便的使用API来实现自己 ...
- Strategy模式
Strategy模式 Strategy模式要解决的问题和Template模式类似.都是为了把算法的声明和算法的实现解耦.Template模式是通过继承来实现的,而Strategy模式是通过组合来实现的 ...
- UML序列图
先准备好之前的类图,然后在最开始的地方新添加一个版块“交互设计” Add Diagram --> Sequence Diagram Add --> Actor建立一个user 然后就可以拖 ...