题目链接(https://codeforces.com/gym/102769/problem/F)
F. Friendly Group
time limit per test 2.0 s
memory limit per test 512 megabytes
input standard input
output standard output
Professor Alex will organize students to attend an academic conference.
Alex has n n n excellent students, and he decides to select some of them (possibly none) to attend the conference. They form a group. Some pairs of them are friends.
The friendly value of the group is initially 0 0 0. For each couple of friends ( x , y ) (x,y) (x,y), if both of them attend the conference, the friendly value of the group will increase 1 1 1, and if only one of them attends the conference, the friendly value of the group will decrease 1 1 1. If k k k students attend the conference, the friendly value of the group will decrease k k k.
Alex wants to make the group more friendly. Please output the maximum friendly value of the group.
Input
The first line of the input gives the number of test cases, T ( 1 ≤ T ≤ 1 0 4 ) T (1≤T≤10^4) T(1≤T≤104). T T T test cases follow.
For each test case, the first line contains two integers n ( 1 ≤ n ≤ 3 × 1 0 5 ) n (1≤n≤3×10^5) n(1≤n≤3×105) and m ( 1 ≤ m ≤ 1 0 6 ) m (1≤m≤10^6) m(1≤m≤106), where n n n is the number of students and mm is the number of couples of friends.
Each of the following mm lines contains two integers x i , y i ( 1 ≤ x i , y i ≤ n , x i ≠ y i ) xi,yi (1≤xi,yi≤n,xi≠yi) xi,yi(1≤xi,yi≤n,xi=yi), representing student$ xi$ and student y i yi yiare friends. It guaranteed that unordered pairs$ (xi,yi)$ are distinct.
The sum of n n n in all test cases doesn’t exceed 1 0 6 10^6 106, and the sum of m m m in all test cases doesn’t exceed 2 × 1 0 6 2×10^6 2×106.
Output
For each test case, output one line containing “Case #x: y”, where x x x is the test case number (starting from 1 1 1), and y y y is the maximum friendly value of the group.
Example
input
2
4 5
1 2
1 3
1 4
2 3
3 4
2 1
1 2
output
Case #1: 1
Case #2: 0
题意
给定 n n n个学生,其中有 m m m对好朋友 ( x , y ) (x,y) (x,y),老师要挑选一些学生去比赛,设定这群学生友谊值初始为0,
如果一对好朋友都被挑选到,群体友谊值 + 1 +1 +1,如果一对好朋友当中只有其中一人被选中,群体友谊值 − 1 -1 −1,如果有 k k k个学生参加了比赛,群友谊值 − k -k −k,问挑选出学生群最大友谊值是多少。
思路
根据样例画图发现, 答 案 数 = 通 路 数 − 人 数 答案数=通路数-人数 答案数=通路数−人数
继续加边发现,单条的边对通路贡献为1,对人数t贡献也为1,所以单成链的边对答案没有贡献,只有单独的环路贡献为正
继续考虑,环套环,也是没有影响的
求通路最常用的算法为并查集,故以并查集模板
最后,差点以为是求友谊值最大的群,队友最后提出了群体不止一个(不好好读题的锅),所以把每个环路的正贡献相加即可
AC代码
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define llinf 0x3f3f3f3f3f3f3f3f
#define int long long
#define ull unsigned long long
#define PII pair<int,int>
using namespace std;
typedef long long LL;
const int N = 3e5 + 100;
const int mod = 1e9 + 7;
const double pi = acos(-1.0);
int t, n, m;
int root[N];
int road[N];//同一集合通路数
int cnt[N];//同一集合人数
int ans;
void init() {//初始化
for (int i = 0; i <= n; i++) {
root[i] = i;//初始以自己为根
road[i] = 0;//初始没通路
cnt[i] = 1;//初始只有自己一个人
}
return;
}
int find(int x) { return x == root[x] ? x : root[x] = find(root[x]); }//路径压缩
void merge(int x, int y) {
int dx = find(x);
int dy = find(y);
if (dx != dy) {//不同根
cnt[dx] += cnt[dy];//集合人数叠加
road[dx] += road[dy];//集合通路数叠加
//并根在增加操作之后
root[dy] = dx;
road[dx] ++;//并根时增加的一条通路
}
else {//同根,只有通路数增加
road[dx] ++;
}
return;
}
void solve() {
init();
int x, y;
while (m--) {//加边操作
cin >> x >> y;
if (y < x) swap(x, y);//这里我默认前面比后面的序号大,不知道对merge有没有影响
merge(x, y);
}
ans = 0;
for (int i = 1; i <= n; i++) {
if (root[i] == i) {
int t = road[i] - cnt[i];
if (t >= 0) ans += t;//如果贡献为正就相加
}
}
return;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> t;
for (int i = 1; i <= t; i++) {
cin >> n >> m;
solve();
cout << "Case #" << i << ": " << ans << endl;//输出
}
return 0;
}