题解:(以下内容出自题解没错但是代码有错却过了bzoj评测的hwzer学长)先求出最小生成树,要严格次小。枚举每一条非树边找俩顶点树链上的最大边(如果最大边相同与非树边边权相同则找次大边)然后更新最小增量。最大边和次大边可以通过树上倍增求出。
下证hzwer学长和其他一些同学的错误,以hzwer的代码为例:
void cal(int x,int f,int v)
{
int mx1=0,mx2=0;
int t=deep[x]-deep[f];
for(int i=0;i<=16;i++)
{
if(t&(1<<i))
{
if(d1[x][i]>mx1)
{
mx2=mx1;
mx1=d1[x][i];
}
mx2=max(mx2,d2[x][i]);
x=fa[x][i];
}
}
if(mx1!=v)mn=min(mn,v-mx1);
else mn=min(mn,v-mx2);
}
先用文字说一遍:当之前已算过的最大值大于当期的最大值时,当前最大值可以用来更新次大值,他并没有这么做。再用代码解释一遍:当mx1>d1[x][i]时,d1[x][i]可以用来更新mx2,而他并没有这么做。
再说说如何hack掉这类代码:
方案1.出一组如下数据(就是将样例的点的编号进行一些交换):
5 6
1 2 2
1 5 4
2 3 1
3 4 3
1 4 3
5 4 6
答案是11,典型错误是12。
方案2.直接将hzwer的dfs(1)改为dfs(3),次小生成树的大小与根的选取无关,但是它跑出了错误的答案(12)。
P.S.WA了一大晚上因为kruskal没sort。。。但是在调试过程中有了这么多新发现也算值了。
下面是严格的正解
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<utility>
using namespace std;
typedef long long ll;
#define pii pair<int ,int >
#define mp(x,y) make_pair(x,y)
const int MAXN=1e5+4,MAXM=3e5+4;
int n,m,mm=0,root;
int head[MAXN],etot=0;
struct EDGE {
int v,nxt,w;
}e[MAXN<<1];
int dep[MAXN],mx[18][MAXN],ms[18][MAXN],f[18][MAXN];
ll mst=0;
int delta=0x3f3f3f3f;
inline int read() {
int x=0;char c=getchar();
while (c<'0'||c>'9') c=getchar();
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x;
}
inline void adde(int u,int v,int w) {
e[etot].nxt=head[u],e[etot].v=v,e[etot].w=w,head[u]=etot++;
e[etot].nxt=head[v],e[etot].v=u,e[etot].w=w,head[v]=etot++;
}
/*---------------kruskal---------------*/
struct M_EDGE {
int u,v,w;
friend bool operator <(const M_EDGE &a,const M_EDGE &b) {
return a.w<b.w;
}
}d[MAXM];
int fa[MAXN];
bool sel[MAXM];
inline int find(int x) {
return fa[x]==x?x:fa[x]=find(fa[x]);
}
inline void kruskal() {
sort(d+1,d+m+1);
memset(sel,false,sizeof(sel));
int blo=n;
for (register int i=1;i<=m&&blo>1;++i) {
int u=find(d[i].u),v=find(d[i].v);
if (u^v) {
mst+=d[i].w;
fa[u]=v,--blo;
adde(d[i].u,d[i].v,d[i].w);
sel[i]=true;
root=d[i].u;
}
}
}
/*---------------LCA---------------*/
void dfs(int p,int father) {
f[0][p]=father,dep[p]=dep[father]+1;
for (int i=head[p];~i;i=e[i].nxt) {
int v=e[i].v;
if (v^father) {
mx[0][v]=e[i].w;
dfs(v,p);
}
}
}
inline void da() {
for (int j=1;(1<<j)<=n;++j)
for (register int i=1;i<=n;++i) {
mx[j][i]=max(mx[j-1][i],mx[j-1][f[j-1][i]]);
ms[j][i]=max(ms[j-1][i],ms[j-1][f[j-1][i]]);
if (mx[j-1][i]^mx[j-1][f[j-1][i]]) ms[j][i]=max(ms[j][i],min(mx[j-1][i],mx[j-1][f[j-1][i]]));
f[j][i]=f[j-1][f[j-1][i]];
}
}
inline void update(int x,int y,int weight) {
int m1=0,m2=0,a,b,c,d;
if (dep[x]<dep[y]) x^=y^=x^=y;
int t=dep[x]-dep[y];
for (int i=0;i<=17;++i)
if (t&(1<<i)) {
a=mx[i][x],b=ms[i][x],c=m1,d=m2;
m1=max(a,c),m2=max(b,d);
if (a^c) m2=max(m2,min(a,c));
x=f[i][x];
}
if (x==y) {
if (m1^weight) delta=min(delta,weight-m1);
delta=min(delta,weight-m2);
return ;
}
for (int i=17;~i;--i)
if (f[i][x]^f[i][y]) {
a=mx[i][x],b=ms[i][x],c=m1,d=m2;
m1=max(a,c),m2=max(b,d);
if (a^c) m2=max(m2,min(a,c));
a=mx[i][y],b=ms[i][y],c=m1,d=m2;
m1=max(a,c),m2=max(b,d);
if (a^c) m2=max(m2,min(a,c));
x=f[i][x],y=f[i][y];
}
a=mx[0][x],b=ms[0][x],c=m1,d=m2;
m1=max(a,c),m2=max(b,d);
if (a^c) m2=max(m2,min(a,c));
a=mx[0][y],b=ms[0][y],c=m1,d=m2;
m1=max(a,c),m2=max(b,d);
if (a^c) m2=max(m2,min(a,c));
if (m1^weight) delta=min(delta,weight-m1);
delta=min(delta,weight-m2);
}
int main() {
// freopen("bzoj 1977.in","r",stdin);
memset(head,-1,sizeof(head));
n=read(),m=read();
for (register int i=1;i<=m;++i) d[i].u=read(),d[i].v=read(),d[i].w=read();
for (register int i=1;i<=n;++i) fa[i]=i;
kruskal();
memset(ms,0,sizeof(ms));
memset(mx,0,sizeof(mx));
dep[0]=0;
dfs(3,0);//dfs谁都可以
da();
for (int i=1;i<=m;++i) {
if (sel[i]) continue;
update(d[i].u,d[i].v,d[i].w);
}
printf("%lld\n",mst+delta);
return 0;
}