【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

5 6
1 2 1
1 3 2
2 4 3
3 5 4
3 4 3
4 5 6

Sample Output

11

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 最小生成树+倍增的更多相关文章

  1. [bzoj1977][BeiJing2010组队]次小生成树 Tree——树上倍增+lca

    Brief Description 求一个无向图的严格次小生成树. Algorithm Design 考察最小生成树的生成过程.对于一个非树边而言,如果我们使用这一条非树边去替换原MST的路径上的最大 ...

  2. 【bzoj1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+权值线段树合并

    题目描述 求一张图的严格次小生成树的边权和,保证存在. 输入 第一行包含两个整数N 和M,表示无向图的点数与边数. 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z ...

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

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

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

    和倍增法求lca差不多,维护每个点往上跳2^i步能到达的点,以及之间的边的最大值和次大值,先求出最小生成树,对于每个非树边枚举其端点在树上的路径的最大值,如果最大值和非树边权值一样则找次大值,然后维护 ...

  5. bzoj1977 [BeiJing2010组队]次小生成树 Tree——严格次小生成树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1977 因为严格,所以要记录到 LCA 的一个次小值: 很快写好,然后改掉一堆错误后终于过了样 ...

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

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

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

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

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

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

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

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

随机推荐

  1. IIC读写AT24C02代码2——串口命令控制多页读写

    通过串口输入 R .W 进行控制程序读写IIC设备.波特率9600bps,晶振115200HZ. main.c /*------------------------------------------ ...

  2. HTTP——HTTP 1.1的详细介绍 Gunicorn不支持HTTP 1.1

    从前面一小节的表格里,我们可以看到,Gunicorn 的一个缺点是不支持HTTP 1.1.那么 HTTP 1.1 究竟是怎么一回事呢?我们选择 HTTP 服务器在什么情况下需要考虑对 HTTP 1.1 ...

  3. Django——20141014深入理解Django HttpRequest HttpResponse的类和实例

    深入理解Django HttpRequest HttpResponse的类和实例 了解META选项 了解中间件 理清所有模板传输模板变量的方式,并作出选择 Django模板系统:如何利用Django模 ...

  4. Joomla详细安装图文教程

    Joomla 详细安装图文教程 第一步,配置网站信息 配置数据库:这里我选择MySQLi,可以根据自己的选择         安装-- 安装完成!

  5. hdu - 4782 - Beautiful Soup(模拟)

    题意:输出一堆乱排版的html标签,去多余空字符,转换为按缩进输出. 题目链接:pid=4782">http://acm.hdu.edu.cn/showproblem.php?pid= ...

  6. ACE消息队列(转)

    1    消息队列 ACE消息队列由三个部分组成:消息队列(ACE_Message_Queue).消息块(ACE_Message_Block).数据块(ACE_Data_Block) 1.1    A ...

  7. 如何查看mysql数据库的引擎/MySQL数据库引擎详解

    一般情况下,mysql会默认提供多种存储引擎,你可以通过下面的查看: 看你的mysql现在已提供什么存储引擎:mysql> show engines; 看你的mysql当前默认的存储引擎:mys ...

  8. 使用AVPlayer制作一个播放器

    代码地址如下:http://www.demodashi.com/demo/11685.html AVPlayer 是一个强大的视频播放器,可以播放多种格式的视频,缺点是没有控制界面,需要自己去实现. ...

  9. event.returnvalue = false的使用

    event.returnvalue false代表不接收事件返回值 <script language="JavaScript"> //Ctrl+s保存 document ...

  10. 用gradle把springboot项目打包成jar

    ``` 用gradle把springboot项目打包成jar ```### build.gradle 中添加 buildscript { repositories { mavenLocal() mav ...