题解
最小代价就一定是最小生成树,
这很显然。
但是这样只有40分,关键还是在判断方案是否唯一。
我们知道最小生成树有一个环切性质,
即在最小生成树中,添加一没有被选中的边,
那么就会构成一个环,而且这条新加进去的边一定是环上最大的边。
先证明一下上面的那个性质:
如果这个环上还有一条比这条新加入的边更大的边,
那我们就用这条新加入的边来替代比大的那条边,
这样我们得到的生成树更优,也就是说原来的树不是最小生成树,
与前提矛盾,所以这条新加进去的边一定是环上最大的边。
如果这环上面有一条与新加入的边相等的边,
那么用这条新加入的边来代替那条与它相等的边,
这样得到的也是最小生成树,原来的树,也是最小生成树,
那么最小生成树的情况就有多种。
我们枚举一条边(x,y)
通过倍增求出x->lca(x,y),y->lca(x,y)路径上的最大值,
与这条边(x,y)的权值作比较,
如果相等,最小生成树就有多种情况。
code
#include<cstdio>
#include<iostream>
#include<algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#define ll long long
#define N 200003
#define db double
#define P putchar
#define G getchar
#define mo 1000000007
using namespace std;
char ch;
void read(int &n)
{
n=0;
ch=G();
while((ch<'0' || ch>'9') && ch!='-')ch=G();
int w=1;
if(ch=='-')w=-1,ch=G();
while('0'<=ch && ch<='9')n=n*10+ch-'0',ch=G();
n*=w;
}
struct node
{
int x,y,z;
}a[N*2];
bool cmp(node a,node b)
{
return a.z<b.z;
}
int T,n,m,p,t,f1,f2,root;
int fa[N],f[N][17],g[N][17],deep[N];
int next[N*2],to[N*2],b[N],v[N*2],tot,z[N],top;
bool bz[2*N],vis[N];
ll ans;
int get(int x)
{
if(fa[x]!=x)fa[x]=get(fa[x]);
return fa[x];
}
void ins(int x,int y,int z)
{
next[++tot]=b[x];
to[tot]=y;
v[tot]=z;
b[x]=tot;
}
void dfs(int x)
{
vis[x]=0;
//printf("%d\n",deep[x]);
for(int i=b[x];i;i=next[i])
if(vis[to[i]])
{
f[to[i]][0]=x;
deep[to[i]]=deep[x]+1;
g[to[i]][0]=v[i];
dfs(to[i]);
}
}
int lca(int x,int y)
{
int mx=0;
if(deep[y]>deep[x])swap(x,y);
for(int i=16;i>=0;i--)
if(deep[f[x][i]]>=deep[y])mx=mx<g[x][i]?g[x][i]:mx,x=f[x][i];
if(x==y)return mx;
for(int i=16;i>=0;i--)
if(f[x][i]!=f[y][i])mx=mx<g[x][i]?g[x][i]:mx,x=f[x][i],mx=mx<g[y][i]?g[y][i]:mx,y=f[y][i];
mx=mx<g[x][0]?g[x][0]:mx,mx=mx<g[y][0]?g[y][0]:mx;
return mx;
}
int main()
{
read(T);
while(T--)
{
read(n),read(m);
for(int i=1;i<=m;i++)
read(a[i].x),read(a[i].y),read(a[i].z);
sort(a+1,a+1+m,cmp);
for(int i=1;i<=n;i++)
fa[i]=i;
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
memset(next,0,sizeof(next));
memset(bz,1,sizeof(bz));
p=ans=t=0;
for(int i=1;t<n-1;i++)
{
f1=get(a[i].x);
f2=get(a[i].y);
if(f1!=f2)
{
ins(a[i].x,a[i].y,a[i].z);
ins(a[i].y,a[i].x,a[i].z);
fa[f2]=f1;
ans+=a[i].z;
t++;
bz[i]=0;
}
}
deep[1]=1;
memset(vis,1,sizeof(vis));
//dfs(n/2);
z[1]=top=1;
while(top)
{
int x=z[top];
vis[x]=0;
//printf("%d\n",deep[x]);
while(!vis[to[b[x]]] && b[x]!=0)b[x]=next[b[x]];
if(b[z[top]]==0)
{
top--;
continue;
}
f[to[b[x]]][0]=x;
deep[to[b[x]]]=deep[x]+1;
g[to[b[x]]][0]=v[b[x]];
//dfs(to[i]);
z[++top]=to[b[x]];
b[x]=next[b[x]];
}
for(int j=1;j<17;j++)
for(int i=1;i<=n;i++)
f[i][j]=f[f[i][j-1]][j-1],g[i][j]=max(g[i][j-1],g[f[i][j-1]][j-1]);
for(int i=1;i<=m;i++)
if(bz[i])
{
if(lca(a[i].x,a[i].y)==a[i].z)
{
p=1;
break;
}
}
printf("%lld\n",ans);
if(p==0)printf("Yes\n");else printf("No\n");
}
}