https://codeforces.com/gym/102759/problem/D
自闭场,4题跑路,五点共圆和uestc 7题也太猛了
由于要满足不存在一个3元环中,一条边同时小于另外两条边,那么对于u-v这条边,如果u-w,w-v只有一边存在,那么另一边可以任意变的边就等于这两条边的较小值,如果两条边都不存在,就直接2条1就行了
然后可以发现对于同一个联通分量两个点之间的边一定是确定的,且对于这个联通分量的最大或最小生成树,那些还无法确定的边等于这棵树上两个点路径上最小的那条边最优,而对于那些没有加入这棵生成树中的确定边,必须等于这条路径上的最小边,否则非法直接-1。
那么就直接全局跑最大生成树,从大到小枚举边,那么对于u,v所在的x,y连通块,他们之间所有点对的路径最小值就是这条边,所以ans+=sz[u]*sz[v]*e.l然后再把这两个连通块合并
每个连通块之间的点对就直接全是1了,全加上就行了
最后对每个连通块跑dfs后倍增lca判断那些没加入的边是否等于他两个端点之间路径上的最小值判下合不合法
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxl=3e5+10;
int n,m;ll ans;
int f[maxl],dep[maxl];ll sz[maxl];
int fa[21][maxl],mi[21][maxl];
struct edge
{
int u,v,f;ll val;
}b[maxl];
struct ed{int v;ll l;};
vector<ed> e[maxl];
inline bool cmp(const edge &a,const edge &b)
{
return a.val>b.val;
}
inline int find(int x)
{
if(f[x]!=x)
f[x]=find(f[x]);
return f[x];
}
inline void prework()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d%d%lld",&b[i].u,&b[i].v,&b[i].val),b[i].f=0;
sort(b+1,b+1+m,cmp);
for(int i=1;i<=n;i++)
f[i]=i,sz[i]=1;
ans=0;int x,y;
for(int i=1;i<=m;i++)
{
x=find(b[i].u);y=find(b[i].v);
if(x!=y)
{
b[i].f=1;
ans+=sz[x]*sz[y]*b[i].val;
f[y]=x;sz[x]+=sz[y];
e[b[i].u].push_back(ed{b[i].v,b[i].val});
e[b[i].v].push_back(ed{b[i].u,b[i].val});
}
}
}
inline void dfs(int u,int f,int l)
{
fa[0][u]=f;mi[0][u]=l;dep[u]=dep[f]+1;
for(ed ee:e[u])
if(ee.v!=f)
dfs(ee.v,u,ee.l);
}
inline int milca(int u,int v)
{
int ret=b[1].val;
if(dep[u]<dep[v])
swap(u,v);
for(int k=20;k>=0;k--)
if((dep[u]-dep[v])>>k&1)
{
ret=min(ret,mi[k][u]);
u=fa[k][u];
}
if(u==v)
return ret;
for(int k=20;k>=0;k--)
if(fa[k][u]!=fa[k][v])
{
ret=min(ret,mi[k][u]);
ret=min(ret,mi[k][v]);
u=fa[k][u];v=fa[k][v];
}
ret=min(ret,mi[0][u]);ret=min(ret,mi[0][v]);
return ret;
}
inline void mainwork()
{
ll sum=0;
for(int i=1;i<=n;i++)
if(f[i]==i)
{
sum+=sz[i]*(n-sz[i]);
for(ed ee:e[i])
dfs(ee.v,i,ee.l);
}
for(int k=1;k<=20;k++)
for(int i=1;i<=n;i++)
{
fa[k][i]=fa[k-1][fa[k-1][i]];
mi[k][i]=min(mi[k-1][i],mi[k-1][fa[k-1][i]]);
}
for(int i=1;i<=m;i++)
if(!b[i].f)
{
if(b[i].val!=milca(b[i].u,b[i].v))
{
ans=-1;
return;
}
}
ans+=sum/2;
}
inline void print()
{
printf("%lld\n",ans);
}
int main()
{
prework();
mainwork();
print();
return 0;
}