非常好的一道练习并查集的题目,逆向思维很巧妙
#include <iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int M = 5e4 + 10;
const int D = 1e3+10;
typedef pair<int, int>PII;
vector<int>a[M];//用来存边
int n, m, d;
int lock[D];//用来存第i天封锁的机场编号
int p[M];
int ans[D];//存第i天的答案
int find(int x) {
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> m >> d;
vector<PII>query[D];//用来存第i天的所有查询
for(int i=1;i<=n;i++) p[i] = i;
for (int i = 0; i < m; i++) {
int s, t;
cin >> s >> t;
a[s].push_back(t);
a[t].push_back(s);
}
for (int i = 1; i <= d; i++) {
int s,Q;
cin >>s>> Q;
lock[i] = s;
p[s] = 0;
vector<PII> temp;
for (int j = 0; j < Q; j++) {
int w, t;
cin >> w >> t;
temp.push_back({w,t});
}
query[i] = temp;
}
//逆向思维,从最后一天开始,依次将被封锁的航班的所有邻边进行一次union,但是会出现将已经封锁的边也union的情况,
//需要进行判断
for (int i = 1; i <= n; i++) {
if (p[i]) {
for (int j = 0;j<a[i].size();j++){
int t = a[i][j];
if(p[t]) p[find(t)] = find(i);
}
}
}
for (int i = d; i >= 1; i--) {
for (int j = 0; j < query[i].size(); j++) {
auto t = query[i][j];
if (find(t.first)!= find(t.second)|| find(t.first) == 0 || find(t.second) == 0) ans[i]++;
}
int s = lock[i];
p[s] =s;
for (int j = 0; j < a[s].size(); j++) {
int t = a[s][j];//将lock[i]的所有非封锁邻边union
if (p[t]) p[find(s)]= find(t);
}
}
for (int i = 1; i <= d; i++) cout << ans[i]<<endl;
return 0;
}