bzoj1977 次小生成树
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 。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#define REP(i,k,n) for(int i=k;i<=n;i++)
#define in(a) a=read()
#define MAXN 100010
using namespace std;
inline int read(){
int x=,f=;
char ch=getchar();
for(;!isdigit(ch);ch=getchar())
if(ch=='-')
f=-;
for(;isdigit(ch);ch=getchar())
x=x*+ch-'';
return x*f;
}
queue <int> Q;
long long sum=,ans=(1ll<<);
int n,m;
int cnt,book[MAXN<<],f[MAXN];
int vis[MAXN],depth[MAXN],tree[MAXN][],maxx[MAXN][],maxn[MAXN][];
int total=,head[MAXN],to[MAXN<<],nxt[MAXN<<],val[MAXN<<];
struct node{
int x,y,z;
}l[MAXN<<];
bool cmp(node a,node b){
return a.z<b.z;
}
inline int getf(int k){
if(f[k]==k) return k;
return f[k]=getf(f[k]);
}
inline void adl(int a,int b,int c){
total++;
to[total]=b;
val[total]=c;
nxt[total]=head[a];
head[a]=total;
return ;
}
inline void BFS(){//预处理
Q.push();
depth[]=;
vis[]=;
while(!Q.empty()){
int u=Q.front();
Q.pop();
REP(j,,){
tree[u][j]=tree[tree[u][j-]][j-];
if(maxx[u][j-]>maxx[tree[u][j-]][j-]){
maxx[u][j]=maxx[u][j-];
maxn[u][j]=max(maxx[tree[u][j-]][j-],maxn[u][j-]);
}
if(maxx[u][j-]<maxx[tree[u][j-]][j-]){
maxx[u][j]=maxx[tree[u][j-]][j-];
maxn[u][j]=max(maxx[u][j-],maxn[tree[u][j-]][j-]);
}
if(maxx[u][j-]==maxx[tree[u][j-]][j-]){
maxx[u][j]=maxx[u][j-];
maxn[u][j]=max(maxn[u][j-],maxn[tree[u][j-]][j-]);
}
}
for(int e=head[u];e;e=nxt[e])
if(!vis[to[e]]){
vis[to[e]]=;
depth[to[e]]=depth[u]+;
tree[to[e]][]=u;
maxx[to[e]][]=val[e];
Q.push(to[e]);
}
}
return ;
}
inline int lca(int u,int v,int c){//lca
if(depth[u]<depth[v]) swap(u,v);
int d=depth[u]-depth[v];
int ma=-;
for(int i=;(<<i)<=d;i++)//提到同一高度
if((<<i)&d){
if(maxx[u][i]==c) ma=max(ma,maxn[u][i]);
else ma=max(ma,maxx[u][i]);
u=tree[u][i];
// cout<<u<<" "<<ma<<endl;
}
if(u==v){
if(ma==-) return ;
return ma;
}
for(int i=;i>=;i--)//两点开跑
if(tree[u][i]!=tree[v][i]){
if(maxx[u][i]==c && maxx[v][i]==c)
ma=max(ma,max(maxn[u][i],maxn[v][i]));
if(maxx[u][i]==c && maxx[v][i]!=c)
ma=max(ma,max(maxn[u][i],maxx[v][i]));
if(maxx[v][i]==c && maxx[u][i]!=c)
ma=max(ma,max(maxn[v][i],maxx[u][i]));
if(maxx[u][i]!=c && maxx[v][i]!=c)
ma=max(ma,max(maxx[v][i],maxx[u][i]));
u=tree[u][i];
v=tree[v][i];
}//最后lca是他们的父亲,所以要再更新一次
if(maxx[u][]==c && maxx[v][]==c)
ma=max(ma,max(maxn[u][],maxn[v][]));
if(maxx[u][]==c && maxx[v][]!=c)
ma=max(ma,max(maxn[u][],maxx[v][]));
if(maxx[v][]==c && maxx[u][]!=c)
ma=max(ma,max(maxn[v][],maxx[u][]));
if(maxx[u][]!=c && maxx[v][]!=c)
ma=max(ma,max(maxx[v][],maxx[u][]));
return ma;
}
int main(){
in(n);in(m);
REP(i,,n) f[i]=i;
REP(i,,m){
in(l[i].x);
in(l[i].y);
in(l[i].z);
}
sort(l+,l+m+,cmp);
REP(i,,m){
int f1=getf(l[i].x),f2=getf(l[i].y);
if(f1!=f2){
cnt++;
book[i]=;
f[f2]=f1;
sum+=(long long)l[i].z;
adl(l[i].x,l[i].y,l[i].z);
adl(l[i].y,l[i].x,l[i].z);
}
if(cnt==n-) break;
}
BFS();
REP(i,,m)
if(!book[i]){//枚举所有的非树边
// cout<<l[i].x<<" "<<l[i].y<<" "<<l[i].z<<endl;
// cout<<lca(l[i].x,l[i].y,l[i].z)<<endl;
ans=min(ans,sum-(long long)lca(l[i].x,l[i].y,l[i].z)+(long long)l[i].z);
}
cout<<ans;
}
bzoj1977 次小生成树的更多相关文章
- bzoj1977次小生成树(重要)
#include<cstdio> #include<iostream> #include<cstring> #include<queue> #inclu ...
- 2018.09.15 bzoj1977:次小生成树 Tree(次小生成树+树剖)
传送门 一道比较综合的好题. 由于是求严格的次小生成树. 我们需要维护一条路径上的最小值和次小值. 其中最小值和次小值不能相同. 由于不喜欢倍增我选择了用树链剖分维护. 代码: #include< ...
- 【BZOJ1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+倍增
[BZOJ1977][BeiJing2010组队]次小生成树 Tree Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C ...
- 【次小生成树】bzoj1977 [BeiJing2010组队]次小生成树 Tree
Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了.小 P 说,让小 C 求出一 ...
- 严格次小生成树(Bzoj1977:[Beijing2010组队]次小生成树)
非严格次小生成树 很简单,先做最小生成树 然后枚举没加入的边加入,替换掉这个环内最大的边 最后取\(min\) 严格次小生成树 还是一样的 可以考虑维护一个严格次大值 最大值和枚举的边相同就替换次大值 ...
- [BZOJ1977]严格次小生成树
[问题描述] 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等. 正当小C洋洋得意之时,小P又来泼小C冷水了.小P说,让小C求出一个无向图的次小生成树,而且这个次小生成 ...
- [BZOJ1977][BeiJing2010组队]次小生成树
题解: 首先要证明一个东西 没有重边的图上 次小生成树由任何一颗最小生成树替换一条边 但是我不会证啊啊啊啊啊啊啊 然后就很简单了 枚举每一条边看看能不能变 但有一个特殊情况就是,他和环上的最大值相等, ...
- 【bzoj1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+权值线段树合并
题目描述 求一张图的严格次小生成树的边权和,保证存在. 输入 第一行包含两个整数N 和M,表示无向图的点数与边数. 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z ...
- [bzoj1977][BeiJing2010组队]次小生成树 Tree——树上倍增+lca
Brief Description 求一个无向图的严格次小生成树. Algorithm Design 考察最小生成树的生成过程.对于一个非树边而言,如果我们使用这一条非树边去替换原MST的路径上的最大 ...
随机推荐
- Mysql储存过程3:if语句
--if/else语句 if 条件 then SQL语句 else SQL语句elseifSQL语句 end if; create procedure test1( number int ) begi ...
- 关于parse_str变量覆盖分析
这个漏洞有两个姿势.一个是不存在的时候一个是存在的时候. 经过测试该漏洞只在php5.2中存在,其余均不存在. 倘若在parse_str函数使用的代码上方未将其定义那么即存在变量覆盖漏洞否则不行. 还 ...
- 某线下赛AWD
拿别人比赛的来玩一下,或许这就是菜的力量吧. 0x01 任意文件读取: switch ($row['media_type']) { case 0: // 图片广告 ...... break; case ...
- 千字短文解决工程师们关于SPI的迷糊!
串行外设接口 (SPI) 总线是一个工作在全双工模式下的同步串行数据链路.它可用于在单个主控制器和一个或多个从设备之间交换数据.其简单的实施方案只使用四条支持数据与控制的信号线(图 1): 图1:基本 ...
- 设计模式--工厂模式 caffe_layer注册
来源:http://www.cnblogs.com/zhouqiang/archive/2012/07/20/2601365.html 来源:http://blog.luoyetx.com/2016/ ...
- 终止函数 atexit()
函数名: atexit 头文件:#include<stdlib.h> 功 能: 注册终止函数(即main执行结束后调用的函数) 用 法: int atexit(void (*f ...
- system()函数
windows下system () 函数详解 windows操作系统下system () 函数详解(主要是在C语言中的应用) 函数名: system 功 能: 发出一个DOS命令 用 法: i ...
- linux crontab 常用时间设置
时间格式 分钟 小时 日期 月份 周 命令 数字范围 0-59 0-23 1-31 1-12 0-7 echo "hello" >> abc.log 特殊字符的含义 * ...
- python datetime 时区(timezone) dateutil
记录下python中的时区问题, 代码如下: 包括datetime.datetime对象使用不同的时区,以及在不同时区间转换. from datetime import datetime from ...
- 洛谷 P2871 [USACO07DEC]手链Charm Bracelet 题解
题目传送门 这道题明显就是个01背包.所以直接套模板就好啦. #include<bits/stdc++.h> #define MAXN 30000 using namespace std; ...