题目链接
题目大意
n个点,m条路径,d次询问,每次锁定一个点c,给出q条边,问,q条边在锁定c点后多少条边无法连通
题解
并查集支持加一些点进去来判断是不是在一个集合,但是如果删去一个点就不知道多少个点会受影响,所以,这道题的精华就是倒过来,先将那些从来没有锁定的点构建并查集,然后倒过来处理,每次释放一个点,并查集维护没有锁定点的集合。
代码
#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#define x first
#define y second
#define endl '\n'
#define IOS \
ios_base::sync_with_stdio(0); \
cin.tie(0); \
cout.tie(0);
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef pair<int, int> pii;
typedef unsigned long long ull;
const int INF = 0x3f3f3f3f, mod = 1000000007;
const int N = 2e5 + 10;
int n, m, d;
int day[N], p[N];
vector<int> a[N];
vector<pii> v[N];
map<int, int> vis;
int find(int x)
{
if (x != p[x])
p[x] = find(p[x]);
return p[x];
}
void solve()
{
cin >> n >> m >> d;
for (int i = 1; i <= n; i++) {
p[i] = i;
}
for (int i = 1; i <= m; i++) {
int x, y;
cin >> x >> y;
a[x].push_back(y);
a[y].push_back(x);
}
for (int i = 1; i <= d; i++) {
int c, q;
cin >> c >> q;
day[i] = c;
vis[c] = 1;
while (q--) {
int x, y;
cin >> x >> y;
v[i].push_back({x, y});
}
}
for(int i = 1; i <= n; i++){
if(vis[i]) continue;
for(auto x : a[i]){
if(vis[x]) continue;
int fx = find(x), fy = find(i);
if(fx != fy) p[fx] = fy;
}
}
stack<int> q;
for (int i = d; i; i--) {
int cnt = 0, c = day[i];
for(auto x : v[i]){
int fx = find(x.x), fy = find(x.y);
if(fx != fy) cnt++;
}
q.push(cnt);
for(auto x : a[c]){
if(vis[x]) continue;
int fx = find(x), fy = find(c);
if(fx != fy) p[fx] = fy;
}
vis[c] = 0;
}
while (q.size()) {
cout << q.top() << endl;
q.pop();
}
}
int main()
{
// IOS;
int _ = 1;
// cin >> _;
while (_--) {
solve();
}
return 0;
}