#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
#define Maxn 300010
#define maxn 300005
using namespace std;
#define ll long long
struct edge{
int to,w,nxt;
}edge[Maxn];
int head[Maxn/],tot;
void addedge(int a,int b,int c){
edge[tot].to=b;
edge[tot].w=c;
edge[tot].nxt=head[a];
head[a]=tot++;
}
struct line{
int u,v,w;
bool operator<(const line &a)const{
return w<a.w;
}
}q[Maxn]; int vis[Maxn];
int fa[Maxn/];
int findset(int x){
return fa[x]==x?x:(fa[x]=findset(fa[x]));
}
int unionset(int a,int b){
return fa[findset(a)]=findset(b);
}
ll d[maxn],f[maxn][],dp[maxn][][];//dp[i][j][0|1]用来表示向上倍增的最大边,严格次大边
void bfs(){
queue<int>q;
q.push();
d[]=;
while(!q.empty()){
int x=q.front();q.pop();
for(int i=head[x];i!=-;i=edge[i].nxt){
int y=edge[i].to;
if(d[y])continue;
d[y]=d[x]+;
f[y][]=x;
dp[y][][]=edge[i].w;
dp[y][][]=-0x3f3f3f3f;
for(int k=;k<=;k++){
f[y][k]=f[f[y][k-]][k-];
int a=dp[y][k-][];//y向上下一半的最大值
int b=dp[y][k-][];//y向上下一半的严格次大值
int c=dp[f[y][k-]][k-][];//y向上上一半的最大值
int d=dp[f[y][k-]][k-][];//y向上上一半的严格次大值
dp[y][k][]=max(a,c);
if(a==c)dp[x][k][]=max(b,d);
else if(a>c)dp[x][k][]=max(c,b);
else if(a<c)dp[x][k][]=max(a,d);
}
q.push(y);
}
}
}
inline void calc(ll &val1,ll &val2,ll a,ll b){//更新最大和次大
if(a<=val1)val2=max(a,val2);
else val2=val1,val1=a;
}
int lca(int x,int y,int z){//处理加入(x,y,z)后的次小生成树
ll val1=-,val2=-;
if(d[x]<d[y])swap(x,y);
for(int i=;i>=;i--)
if(d[f[x][i]]>=d[y]){
calc(val1,val2,dp[x][i][],dp[x][i][]);
x=f[x][i];
}
if(x==y){
if(val1!=z)return val1;
return val2;
} for(int i=;i>=;i--)
if(f[x][i]!=f[y][i]){
calc(val1,val2,dp[x][i][],dp[x][i][]);
calc(val1,val2,dp[y][i][],dp[y][i][]);
x=f[x][i],y=f[y][i];
}
calc(val1,val2,dp[x][][],dp[x][][]);
calc(val1,val2,dp[y][][],dp[y][][]);
x=f[x][];
if(val1!=z)return val1;
else return val2;
} int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=;i<m;i++)
scanf("%d%d%d",&q[i].u,&q[i].v,&q[i].w);
sort(q,q+m);
for(int i=;i<=n;i++) fa[i]=i;
memset(head,-,sizeof head);
memset(vis,,sizeof vis);
tot=;
int cnt=;
long long ans=;
for(int i=;i<m;i++){
int u=q[i].u,v=q[i].v;
if(findset(u)==findset(v)) continue;
unionset(u,v);
vis[i]=;
addedge(u,v,q[i].w);
addedge(v,u,q[i].w);
ans+=q[i].w;
if(++cnt==n-) break;
}
bfs();
int z=0x3f3f3f3f;
for(int i=;i<m;i++)
if(!vis[i]) {
int t=lca(q[i].u,q[i].v,q[i].w);
if(t>)z=min(z,-t+q[i].w);
}
printf("%lld\n",ans+z);
return ;
}

bzoj1977次小生成树(重要)的更多相关文章

  1. 2018.09.15 bzoj1977:次小生成树 Tree(次小生成树+树剖)

    传送门 一道比较综合的好题. 由于是求严格的次小生成树. 我们需要维护一条路径上的最小值和次小值. 其中最小值和次小值不能相同. 由于不喜欢倍增我选择了用树链剖分维护. 代码: #include< ...

  2. bzoj1977 次小生成树

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

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

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

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

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

  5. 严格次小生成树(Bzoj1977:[Beijing2010组队]次小生成树)

    非严格次小生成树 很简单,先做最小生成树 然后枚举没加入的边加入,替换掉这个环内最大的边 最后取\(min\) 严格次小生成树 还是一样的 可以考虑维护一个严格次大值 最大值和枚举的边相同就替换次大值 ...

  6. [BZOJ1977]严格次小生成树

    [问题描述] 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等. 正当小C洋洋得意之时,小P又来泼小C冷水了.小P说,让小C求出一个无向图的次小生成树,而且这个次小生成 ...

  7. [BZOJ1977][BeiJing2010组队]次小生成树

    题解: 首先要证明一个东西 没有重边的图上 次小生成树由任何一颗最小生成树替换一条边 但是我不会证啊啊啊啊啊啊啊 然后就很简单了 枚举每一条边看看能不能变 但有一个特殊情况就是,他和环上的最大值相等, ...

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

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

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

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

随机推荐

  1. timestamp的妙用

    代码 -- 卖家(登录后台使用, 卖家登录之后可能直接采用微信扫码登录,不使用账号密码) create table `seller_info` ( `id` varchar(32) not null, ...

  2. SQL攻击-预编译--缓存

    PreparedStatement l 它是Statement接口的子接口: l 强大之处: 防SQL攻击: 提高代码的可读性.可维护性: 提高效率! l 学习PreparedStatement的用法 ...

  3. ListBox滚动条 刷新列表之后 指定位置(置顶或滚动到最后)

    参数ObservableCollection<T>类型 滚动条在最上 ListBox.ScrollIntoView(ListBoxOC[0]);滚动条在最下 ListBox.ScrollI ...

  4. DataGrid 查出一个列 按要求显示格式 例如:操作人(地点)

    这是转换DataGrid显示格式之后 连接字符串的方法 显示:操作人(地点) public static ObservableCollection<CListModel> AllUserL ...

  5. Python学习笔记-条件语句

    学习代码如下 flag=False name = raw_input("请输入:"); if name == '羊爸爸': flag=True print 'Welcome Hom ...

  6. 使用@Valid和BindingResult验证请求参数的合法性并处理校验结果

    /** * 添加用户,使用@RequestBody将请求体映射到Action方法参数中 * 使用@Valid注解验证请求参数的合法性 * 使用BindingResult处理校验结果 * @param ...

  7. dubbo源码分析7——dubbo的配置解析_与spring的整合

    dubbo的配置其实就是建立在spring的命名空间的配置机制之上的.在dubbo的jar包的META-INF目录下会有spring.handlers这个文件,用来配置spring的命名空间和解析类的 ...

  8. 【转】STL中vector、list、deque和map的区别

    1.vector 向量 相当于一个数组 在内存中分配一块连续的内容空间进行存储.支持不指定vector大小的存储.STL内部实现时,首先分配一个非常大的内存空间预备进行存储,即capacity()函数 ...

  9. codeforces 462div.2

    A A Compatible Pair standard input/output 1 s, 256 MB    x1916 B A Prosperous Lot standard input/out ...

  10. ffmpeg 加载双语字幕

    set infile=in.mp4 set subfile1=cn.srt set subfile2=en.srt set subvf1="subtitles=%subfile1%:forc ...