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);
}
posted @ 2022-09-15 17:25  ycllz  阅读(23)  评论(0)    收藏  举报