题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1977

因为严格,所以要记录到 LCA 的一个次小值;

很快写好,然后改掉一堆错误后终于过了样例!然而交上去1WA;

又改了半天,还是WA,于是放弃,抄题解好久...

然而就在我调了一个小时终于锁定错误就在那个子函数里的时候才突然看到了自己的明显惊天大错误是怎么回事??!!!稍微改了一下下就完美AC。。。

不过还有点收获,把求各种层次的 f 放在 dfs 函数里会比单独拿出来再求一遍快 1000+ms 哦~

题解的写法是直接看 u 到 lca 和 v 到 lca 路上的值,而我是求 lca 的过程中求值的,还是喜欢我的写法;

题解的写法放在注释里了;

囧。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int const maxn=1e5+,maxm=3e5+,inf=1e9;
int n,m,f[maxn][],dep[maxn],mx[maxn][],nmx[maxn][];//
int hd[maxn],ct,fa[maxn],d[maxn],mnn;
ll ans;//ll
bool vis[maxn],used[maxm];
struct P{int u,v,w;}e[maxm];
struct T{
int mx,nmx;
T(int x=,int n=):mx(x),nmx(n) {}
};
struct N{
int to,nxt,w;
N(int t=,int n=,int w=):to(t),nxt(n),w(w) {}
}ed[maxn<<];
bool cmp(P x,P y){return x.w<y.w;}
void add(int x,int y,int w){ed[++ct]=N(y,hd[x],w); hd[x]=ct;}
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
void dfs(int x)
{
for (int i=; i<=; i++)//写在这里较快
{
if(dep[x]<(<<i))break;
f[x][i]=f[f[x][i-]][i-];
mx[x][i]=max(mx[x][i-],mx[f[x][i-]][i-]);
if (mx[x][i-]==mx[f[x][i-]][i-])
nmx[x][i]=max(nmx[x][i-],nmx[f[x][i-]][i-]);
else
nmx[x][i]=min(mx[x][i-],mx[f[x][i-]][i-]),
nmx[x][i]=max(nmx[x][i],nmx[x][i-]),
nmx[x][i]=max(nmx[x][i],nmx[f[x][i-]][i-]);
}
vis[x]=;
for(int i=hd[x],u;i;i=ed[i].nxt)
if(!vis[u=ed[i].to])
{
f[u][]=x; dep[u]=dep[x]+;
mx[u][]=ed[i].w;
// nmx[u][0]=ed[i].w;//无!
d[u]=ed[i].w;
dfs(u);
}
}
void init()
{
dep[]=; dfs();
// for(int j=1;j<=20;j++)
// for(int i=1;i<=n;i++)
// {
// int tmx=mx[f[i][j-1]][j-1],tnx=nmx[f[i][j-1]][j-1];
// f[i][j]=f[f[i][j-1]][j-1];
// mx[i][j]=max(mx[i][j-1],tmx);
// if(tmx>mx[i][j-1]) nmx[i][j]=max(mx[i][j-1],tnx);
// else if(tmx==mx[i][j-1]) nmx[i][j]=max(nmx[i][j-1],tnx);
// else nmx[i][j]=max(nmx[i][j-1],tmx);
// }
}
void ch(int &rmx,int &rnx,int tmx,int tnx)
{
if(tmx>rmx)
{
rnx=max(tnx,rmx);
rmx=tmx;
}
else if(tmx==rmx) rnx=max(tnx,rnx);
else rnx=max(rnx,tmx);
}
T lca(int x,int y)
{
if(dep[x]<dep[y])swap(x,y);
int k=dep[x]-dep[y],rmx=-,rnx=-;
for(int i=;i>=;i--)
// if((1<<i)&k){rmx=mx[x][i]; rnx=nmx[x][i]; x=f[x][i];}//x放在后面修改!
if((<<i)&k){ch(rmx,rnx,mx[x][i],nmx[x][i]); x=f[x][i];}//!!!!!!囧
for(int i=;i>=;i--)
if(f[x][i]!=f[y][i])
{
ch(rmx,rnx,mx[x][i],nmx[x][i]);
ch(rmx,rnx,mx[y][i],nmx[y][i]);
x=f[x][i]; y=f[y][i]; //后面改!!
}
if(x!=y) ch(rmx,rnx,max(d[x],d[y]),min(d[x],d[y]));
return T(rmx,rnx);
}
//int LCA(int x,int y)
//{
// if(dep[x]<dep[y])swap(x,y);
// int k=dep[x]-dep[y];
// for(int i=20;i>=0;i--)
// if((1<<i)&k){rmx=mx[x][i]; rnx=nmx[x][i]; x=f[x][i];}
// for(int i=20;i>=0;i--)
// if(f[x][i]!=f[y][i])
// {
// x=f[x][i]; y=f[y][i];
// }
// if(x==y)return x;
// return f[x][0];
//}
//T work(int x,int lca)
//{
// T ret;
// int maxx1=-1,maxx2=-1;
// int d=dep[x]-dep[lca];
// for (int i=0; i<=20; i++)
// if (d&(1<<i))
// {
// ch(maxx1,maxx2,mx[x][i],nmx[x][i]);
// x=f[x][i];
// }
// ret.mx=maxx1,ret.nmx=maxx2;
// return ret;
//}
//T solve(int x)
//{
// T ret;
// int u=e[x].u,v=e[x].v,lca=LCA(u,v);
// T uu=work(u,lca);
// T vv=work(v,lca);
// ret.mx=max(uu.mx,vv.mx);
// if(uu.mx>vv.mx) ret.nmx=max(vv.mx,uu.nmx);
// else if(uu.mx==vv.mx) ret.nmx=max(vv.nmx,uu.nmx);
// else ret.nmx=max(uu.mx,vv.nmx);
// return ret;
//}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++)scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
sort(e+,e+m+,cmp);
for(int i=;i<=n;i++)fa[i]=i;
int cnt=;
for(int i=,u,v;i<=m;i++)
if(find(u=e[i].u)!=find(v=e[i].v))
{
cnt++;
fa[find(u)]=find(v);
used[i]=; ans+=e[i].w;
add(u,v,e[i].w); add(v,u,e[i].w);
if(cnt==n-)break;
}
init();
mnn=inf;
for(int i=;i<=m;i++)
{
if(used[i])continue;
int u=e[i].u,v=e[i].v;
T l=lca(u,v);
// T l=solve(i);
if(e[i].w==l.mx)mnn=min(mnn,e[i].w-l.nmx);
else mnn=min(mnn,e[i].w-l.mx);
}
printf("%lld",ans+mnn);
return ;
}

bzoj1977 [BeiJing2010组队]次小生成树 Tree——严格次小生成树的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. php总结回顾

    做人不能一直埋着头往前跑,还要偶尔停下来看下来时的路.所以今天就来回顾下之前的吧 下面依次介绍 [一]TP加载流程 ①应用入口文件index.php→②tp公共入口文件ThinkPHP.php→③核心 ...

  2. 第二节:Css重写样式

    一丶 进入浏览器---->F12----->找到要修改的区域的Style 进行重写Css样式 二丶打开新页面 window.open("/Persitent/OtherIndex ...

  3. UVA - 208 Firetruck(并查集+dfs)

    题目: 给出一个结点d和一个无向图中所有的边,按字典序输出这个无向图中所有从1到d的路径. 思路: 1.看到紫书上的提示,如果不预先判断结点1是否能直接到达结点d,上来就直接dfs搜索的话会超时,于是 ...

  4. Linux 源码

    https://elixir.bootlin.com/linux/latest/source

  5. x component of 2nd stokes wave--- C code

    * Source code The following is a C code for x component of 2nd stokes wave ××××××××××××××××××××× /*s ...

  6. 在vue中使用echars不能自适应的解决方法

    <div class="echarts"> <IEcharts :option="bar" ref="echarts"&g ...

  7. C,LINUX,数据结构部分

    1604期 第1期测试(面试精选:C,LINUX,数据结构部分) 本试卷从考试酷examcoo网站导出,文件格式为mht,请用WORD/WPS打开,并另存为doc/docx格式后再使用 试卷编号:24 ...

  8. HDU 5115 (2014ACM/ICPC亚洲区北京站) D题(Dire Wolf)

    题目传送门 设dp[i][j]为杀掉区间i到j之间的狼需要付出的最小代价,那么dp[i][j]=min{dp[i][k-1]+dp[k+1][j]+a[k]+b[i-1]+b[j+1]} Java代码 ...

  9. LightOJ 1348 Aladdin and the Return Journey

    Aladdin and the Return Journey Time Limit: 2000ms Memory Limit: 32768KB This problem will be judged ...

  10. 53. spring boot系列合集【从零开始学Spring Boot】

    前40章节的spring boot系列已经打包成PDF在csdn进行发布了,如果有需要的可以进行下载. 下载地址:http://download.csdn.net/detail/linxinglian ...