freee Programming Contest 2022(AtCoder Beginner Contest 264)E
E - Blackout 2
经典删边反着做 变成加边
然后题干提到连通块 我们会很自然的想到并查集 但是多源点 那我们也可以想到一个虚拟超级源点
最后要注意的就是并查集 find 顺序即可 一般我们先加cnt再merge 当然要注意的是我们merge时 一定是合并到超级源点上 就是要指向0
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6+10;
const int M = 998244353;
const int mod = 998244353;
#define int long long
#define endl '\n'
#define all(x) (x).begin(),(x).end()
#define YES cout<<"Yes"<<endl;
#define NO cout<<"No"<<endl;
#define _ 0
#define INF 0x3f3f3f3f3f3f3f3f
#define fast ios::sync_with_stdio(false);cin.tie(nullptr);
int p[N],n,m,e,cnt[N];
pair<int,int>g[N];
vector<int>query;
bool st[N];
int find(int x){
if(p[x]!=x)p[x]=find(p[x]);
return p[x];
}
void merge(int x, int y){
p[find(x)] = find(y);
}
void solve() {
cin>>n>>m>>e;
for(int i=1;i<=n+m;i++)p[i]=i;
for(int i=n+1;i<=n+m;i++)p[i]=0;
for(int i=1;i<=n;i++)cnt[i]=1;
for(int i=1;i<=e;i++){
cin>>g[i].first>>g[i].second;
}
int r;cin>>r;
for(int i=1;i<=r;i++){
int x;cin>>x;
query.push_back(x);
st[x]=1;
}
for(int i=1;i<=e;i++){
int a=g[i].first,b=g[i].second;
if(!st[i]){
a=find(a),b=find(b);
if(a!=b){
p[max(a,b)]=min(a,b);
cnt[min(a,b)]+=cnt[max(a,b)];
}
}
}
vector<int>ans;
for(int i=r-1;i>=0;i--){
auto [a,b]=g[query[i]];
ans.push_back(cnt[0]);
a=find(a),b=find(b);
if(a!=b){
p[max(a,b)]=min(a,b);
cnt[min(a,b)]+=cnt[max(a,b)];
}
}
std::reverse(ans.begin(), ans.end());
for(auto i:ans)cout<<i<<endl;
}
signed main(){
fast
int T;T=1;
while(T--) {
solve();
}
return ~~(0^_^0);
}