NOIP提高模拟-20181016-T2-华莱士

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sdsy191553/article/details/83092010

写在前面

本题是一道很好的题目,本来我是用一个完全错误的做法做的,居然没有被卡,得了 50 p t s 50pts 这么良心的出题人很少见了。

Solution

100 p t s 100pts 做法

仔细观察本题,发现题目所求是 n n 个点 n n 条边的一张图,那么很容易想到是一个环套树。如何维护环套树?很显然,用并查集。
判断是否能加入一条边时,如果这条边的两端已经联通,我们需要知道这个联通块是否有环。 如果不连通,那么可以加入这条边,而且通过两端的联通块是否有环可以得到新的联通块是 否有环。

于是我们用并查集维护连通性,额外维护联通块里是否有环即可。
这样的时间复杂度可以做到 O ( ( n + m ) l o g n ) 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; 
}

猜你喜欢

转载自blog.csdn.net/sdsy191553/article/details/83092010
今日推荐