[Ybtoj Chapter 10 Example 6] Destroy one by one [Combine the collection]

Insert picture description here
Insert picture description here
Insert picture description here
Insert picture description here
Insert picture description here


Problem-solving ideas

Regarding highways as edges, cities as points, and occupied cities as special points, this problem is transformed into an optimal reduction scheme for seeking truth and disconnection between special points.
First of all, we change the direction, do not delete the edges, change to connect edges, and become such a greedy: first arrange the edges in descending order, and then enumerate all edges from the front to the back. If a certain edge is connected, the two special points will not be connected. , Even on this side. The final answer is the total edge weight minus the sum of the connected edge weights.

Consider optimizing time complexity:
we find that there is at most one special point or none in a connected block, and we can use union search to maintain the connected block. If there is a special point in the set, let the special point be the representative element of the set, otherwise any point is fine. To determine whether an edge is connected to two special points, it is enough to directly determine whether the representative element of the set where the two ends are connected is a special point, and to determine whether the two points are connected, it is sufficient to directly determine whether the representative elements of the set are the same. When two sums are combined, if one of the representative elements of a set is a special point, then another set is merged into it to ensure that the special point is always the representative element of the set where it is located.


Code

#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<bitset>
using namespace std;

int n,m,k,x,l[100010],fa[100010];
long long ans;

struct c{
    
    
	int u,v,w;
}a[500010];

bool cmp(c l,c r)
{
    
    
	return l.w>r.w;
}

int find(int x)
{
    
    
	if(x==fa[x])return x;
	else return fa[x]=find(fa[x]);
}

int main(){
    
    
	scanf("%d%d%d",&n,&m,&k);
	for(int i=1;i<=n;i++)
		fa[i]=i;
	for(int i=1;i<=k;i++)
	{
    
    
		scanf("%d",&x);
		l[x+1]=1;
	}
	for(int i=1;i<=m;i++)
	{
    
    
		scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);
		a[i].u++,a[i].v++;//因为从0开始
		ans+=a[i].w;
	}	
	sort(a+1,a+m+1,cmp);
	for(int i=1;i<=m;i++)
	{
    
    
		int xx=find(a[i].u),yy=find(a[i].v);
		if(xx==yy)
			ans-=a[i].w;
		else if(!l[xx]||!l[yy])//至少有一个集合的代表元素不是特殊点
		{
    
    
			ans-=a[i].w;
			if(!l[xx])fa[xx]=yy;//并入特殊点所在的那个集合
			else fa[yy]=xx;
		}
	}
	printf("%lld",ans);
}

Guess you like

Origin blog.csdn.net/kejin2019/article/details/115254599