题意: 给定 n n n点 m m m条无向边,最少需要删除多少条边可以使得所有编号 ≤ k \leq k ≤k的点都不在环上。 数据范围: 1 ≤ n ≤ 1 0 6 , 1 ≤ m ≤ 2 × 1 0 6 , 1 ≤ k ≤ n 1\leq n\leq 10^6, 1\leq m\leq 2\times 10^6, 1\leq k\leq n 1≤n≤106,1≤m≤2×106,1≤k≤n
题解: 构造生成树。
先用所有编号大于 k k k的点连成的边构造生成树。然后用所有存在编号 ≤ k \leq k ≤k的边来构造生成树。当无法加入时,说明该边需删除,否则该边加入生成树即可。代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<set> #include<stack> #include<queue> #include<map> #include<vector> #include<cmath> using namespace std; typedef long long ll; template<typename T> inline T Read(){ T s = 0, f = 1; char ch = getchar(); while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();} while(isdigit(ch)) {s = (s << 3) + (s << 1) + ch - '0'; ch = getchar();} return s * f; } #define read() Read<int>() #define readl() Read<long long>() const int N = 1e6 + 10, M = 2e6 + 10; int p[N]; struct Node{ int a, b; bool operator < (const Node &A) const { return a > A.a; } }e[M]; int find(int x) { if(x != p[x]) p[x] = find(p[x]); return p[x]; } void solve() { int n = read(), m = read(), k = read(); int res = 0; for(int i = 1; i <= n; i++) p[i] = i; for(int i = 1; i <= m; i++) { int a = read(), b = read(); if(a > b) swap(a, b); e[i] = {a, b}; } sort(e + 1, e + m + 1); for(int i = 1; i <= m; i++) { int a = e[i].a, b = e[i].b; int fa = find(a), fb = find(b); if(fa != fb) p[fa] = fb; else if(a <= k) ++res; } printf("%d\n", res); } int main() { int T = 1; //T = read(); for(int i = 1; i <= T; ++i) { solve(); } return 0; }