写在前面
本题是一道很好的题目,本来我是用一个完全错误的做法做的,居然没有被卡,得了
50
p
t
s
50pts
50pts。这么良心的出题人很少见了。
Solution
100 p t s 100pts 100pts做法
仔细观察本题,发现题目所求是
n
n
n个点
n
n
n条边的一张图,那么很容易想到是一个环套树。如何维护环套树?很显然,用并查集。
判断是否能加入一条边时,如果这条边的两端已经联通,我们需要知道这个联通块是否有环。 如果不连通,那么可以加入这条边,而且通过两端的联通块是否有环可以得到新的联通块是 否有环。
于是我们用并查集维护连通性,额外维护联通块里是否有环即可。
这样的时间复杂度可以做到
O
(
(
n
+
m
)
l
o
g
n
)
O((n+m)logn)
O((n+m)logn)
Talk is Cheap, Show You the Code:
#include<bits/stdc++.h>
using namespace std;
#define N 500005
int read(){
int sum=0,neg=1;
char c=getchar();
while(c>'9'||c<'0'&&c!='-') c=getchar();
if(c=='-') neg=-1,c=getchar();
while(c>='0'&&c<='9') sum=(sum<<1)+(sum<<3)+c-'0',c=getchar();
return sum*neg;
}
struct Edge{
int u,v,w;
Edge(int u,int v,int w):u(u),v(v),w(w){}
friend inline bool operator > (const Edge &a,const Edge &b){
return a.w>b.w;
}
};
priority_queue<Edge,vector<Edge>,greater<Edge> > q;
int n,m;
int p[N],type[N],cnt;
long long ans;
int find(int x){
return p[x]==x?x:p[x]=find(p[x]);
}
/* 50pts玄学做法(dzy大佬说可以卡掉,然而我过了50pts,QAQ)
int p[N],r[N],use[N];
bool cmp(const int i,const int j){
if(e[i].w!=e[j].w) return e[i].w<e[j].w;
else if(e[i].u!=e[j].u) return e[i].u<e[j].u;
else return e[i].v<e[j].v;
}
int find(int x){
return p[x]==x?x:p[x]=find(p[x]);
}
long long Kruskal(){
long long ans=0;
for(int i=1;i<=n;i++) p[i]=i;
for(int i=1;i<=2*m;i++) r[i]=i;
sort(r+1,r+2*m+1,cmp);
for(int i=1;i<=2*m;i++){
int ide=r[i];
int x=find(e[ide].u);
int y=find(e[ide].v);
if(x!=y){
ans+=e[ide].w;
p[x]=y;
if(e[ide].u==e[ide+1].v&&e[ide].v==e[ide+1].u)
use[ide]=true,use[ide+1]=true;
if(e[ide].u==e[ide-1].v&&e[ide].v==e[ide-1].u)
use[ide]=true,use[ide-1]=true;
}
}
return ans;
}
signed main(){
n=read(); m=read();
for(int i=1;i<=m;i++){
int u,v,w;
u=read(); v=read(); w=read();
AddEdge(u,v,w);
AddEdge(v,u,w);
}
long long final_ans=Kruskal();
long long weight=0x7ffffffffffffff;
for(int i=1;i<=2*m;i++)
if(!use[i])
weight=min(weight,e[i].w);
if(weight==0x7ffffffffffffff) printf("No\n");
else printf("%d\n",final_ans+weight);
}
*/
int main(){
n=read(); m=read();
for(int i=1;i<=n;i++) p[i]=i;
for(int i=1;i<=m;i++){
int u,v,w;
u=read(); v=read(); w=read();
q.push(Edge(u,v,w));
}
while(!q.empty()){
Edge u=q.top(); q.pop();
int x=find(u.u);
int y=find(u.v);
if(x==y){
if(!type[x]) type[x]=1,ans+=u.w,++cnt;
}
else{
if(type[x]&&type[y]) continue;
p[x]=y; type[y]=type[y]|type[x];
ans+=u.w; ++cnt;
}
}
if(cnt!=n) puts("No");
else printf("%lld\n",ans);
return 0;
}