当前位置: 代码迷 >> 综合 >> [Atcoder NIKKEI Contest 2019]E.Weights on Vertices and Edges(并查集)
  详细解决方案

[Atcoder NIKKEI Contest 2019]E.Weights on Vertices and Edges(并查集)

热度:62   发布时间:2023-10-22 21:58:14.0

即将退役前把之前咕掉的题解补上

题面

Score: 800800800 points
There is a connected undirected graph with NNN vertices and MMM edges. The vertices are numbered 111 to NNN, and the edges are numbered 111 to MMM.
Also, each of these vertices and edges has a specified weight. Vertex iii has a weight of
XiX_iXi?; Edge iii has a weight of YiY_iYi? and connects Vertex AiA_iAi? and BiB_iBi?.
We would like to remove zero or more edges so that the following condition is satisfied:

For each edge that is not removed, the sum of the weights of the vertices in the connected component containing that edge, is greater than or equal to the weight of that edge.

Find the minimum number of edges that need to be removed.
1≤N,M≤1051≤N,M≤10^51N,M105

题解

考试的时候看起来好难的样子,就弃掉颓废去了…

首先显然我们每次删边算联通块是不现实的,因此我们需要计算保留下来的边。
这样我们就可以将边依次加入到图中,算联通块用并查集实现,加入到图中的所有边就是保留下来的边。
考虑到联通块的重量显然是递增的,那么这样,可以接受的边也就越来越多。
那么我们可以尝试按边的重量从小到大排序加入。
考虑新加入一条合并两个联通块的边uuu,vvv,(u≠v)(u≠v)(u??=v)
1.若总重量超过这条边,显然是可行的。
2.如果没有超过,可以用一个cntcntcnt数组暂时记一下,等到再次出现了第一种情况,显然已经达到要求,那么我们就可以将它加进去了。
对于u=vu=vu=v的情况,我们也可以用类似的方法解决。
由于时间问题,详细请参考代码。
O(nα(n))O(n α(n))O(nα(n))

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 100000 
#define LL long long
int n,m,ans;
LL w[MAXN+5];
int fa[MAXN+5],cnt[MAXN+5];
struct edge{
    int u,v,w;
}a[MAXN+5];
bool cmp(edge s1,edge s2){
    return s1.w<s2.w;}
int xfind(int x){
    return (fa[x]==x)?x:fa[x]=xfind(fa[x]);}
int main()
{
    scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){
    scanf("%lld",&w[i]);fa[i]=i;}for(int i=1;i<=m;i++)scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);sort(a+1,a+m+1,cmp);for(int i=1;i<=m;i++){
    int x=xfind(a[i].u),y=xfind(a[i].v);if(x!=y){
    w[x]+=w[y];cnt[x]+=cnt[y];w[y]=0,cnt[y]=0;fa[y]=x;}cnt[x]++;if(w[x]>=a[i].w){
    ans+=cnt[x];cnt[x]=0;}}printf("%d",m-ans);
}