Description
给定一个n个点m条边的无向图,问最少删掉多少条边能使得编号小于等于k的点都不在环上。
n<=1e6 m<=2e6
Solution
一个结论是,我们只会删k个点内部的边和向外连出的边。因为两端点都大于k的边上包含k个点的环肯定不会比内部和连出去的边要多,因此我们这样删一定不会更劣。然后就并查集先把外部边先全部连上,再维护其余边的生成树就行了
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fi first
#define se second
typedef std:: pair <int,int> pair;
const int N=2000005;
std:: vector <pair> edge;
int fa[N];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
int find(int x) {
return !fa[x]?x:fa[x]=find(fa[x]);
}
bool merge(int x,int y) {
x=find(x),y=find(y);
if (x==y) return false;
return (fa[x]=y)|1;
}
int main(void) {
int n=read(),m=read(),k=read(),ans=m;
rep(i,1,m) {
int x=read(),y=read();
if (x>k&&y>k) {
merge(x,y);
ans--; continue;
}
edge.push_back(pair(x,y));
}
for (int i=0;i<edge.size();++i) {
if (merge(edge[i].fi,edge[i].se)) {
ans--;
}
}
printf("%d\n", ans);
return 0;
}