#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. #6279. 数列分块入门 3(询问区间内小于某个值 xx 的前驱(比其小的最大元素))

    题目链接:https://loj.ac/problem/6279 题目大意:中文题目 具体思路:按照上一个题的模板改就行了,但是注意在整块查找的时候的下标问题. AC代码: #include<b ...

  2. 20165221 JAVA第五周学习心得

    课本知识点 内部类与异常类 内部类:在一个类中定义另一个类 特点:外嵌类的成员在内部类仍然有效,内部类也可调用外嵌类的方法,内部类的类体不能声明类变量及类方法 非内部类不能是static类 匿名类:创 ...

  3. java的引用

    一.值类型与引用类型 1.变量初始化 int num = 10; String str = "hello"; num是int基本类型变量,值就直接保存在变量中.str是String ...

  4. 一个是EF内联多表查询,一个是EF中写SQL文。

    public IList<MenuModel> GetAllMenu() { using (IMMEntities context = new IMMEntities()) { var m ...

  5. javascript面向对象学习

    1.this指向问题,指向的是当前的方法属于谁,当前的方法属于谁就指向谁!! 例子: oDiv.onclick = function () { this指向的是oDiv,因为这个方法属于oDiv } ...

  6. vc++基础班[26]---进程的相关操作

      ①.ShellExecute 进行进程的创建,属于 shell api: //int iRet = (int)ShellExecute(m_hWnd, _T("open"), ...

  7. python用类装饰函数的一个有趣实现

    class RunningLog: def __init__(self,func): self._func=func self._func_name = func.__name__ def __cal ...

  8. Mysql安装与配置调优

    一.安装apt-get install mysql-server 需要设置账号密码 apt-get isntall mysql-client apt-get libmysqlclient-dev2.s ...

  9. 遇到一个json解码失败的问题

    今日批量导入游戏, 从别人接口拉去的字符串json_decode总是失败, 但是把log里面记录的解码失败的字符串copy出来单独解析,却可以成功. 排除了是字符编码的问题后, 还是不行, 百思不得其 ...

  10. hibernate框架学习第三天:对象状态、一级缓存、快照等

    对象的状态 瞬时状态: 瞬时对象(TO) 应用程序创建出来的对象,不受H3控制 注意:TO对象不具有OID,一旦为TO赋值OID,那么此时就不是TO 持久化状态:持久化对象(PO) 受H3控制的对象, ...