CF-292-D-并查集

292-D 题目大意

给定一张无向图,由n个顶点m条边。有q次询问,每次询问将[l,r]的边删去,问图中有多少连通分量。


Solution

涉及连通分量,尝试应用并查集解决。

记录一个前缀并查集pre[i],表示前i条边连通后的图;和一个后缀并查集suf[i],表示后mi条边连通后的图。

对于一个询问[l,r],把pre[l1]suf[r+1]两个并查集拼起来,再统计连通分量即可。

时间复杂度O((m+qn)α(n))

#include<bits/stdc++.h>
using namespace std;
using ll=long long;

template<typename T>
struct DSU{
	int n;
	vector<T> p,siz;
	DSU(int _n):p(_n+1),siz(_n+1),n(_n){
		iota(p.begin(),p.end(),0);
		for(int i=0;i<=n;i++) siz[i]=1;
	}
	T findd(T x){
		return p[x]==x?x:p[x]=findd(p[x]);
	}
	void unionn(T x,T y){
		x=findd(x),y=findd(y);
		if(x==y) return;
		if(siz[x]>siz[y]) swap(x,y);
		p[x]=y;
		siz[y]+=siz[x];
	}
};

void solve(){
    int n,m;
    cin>>n>>m;
    vector<DSU<int>> pre(m+2,DSU<int>(n)),suf(m+2,DSU<int>(n));
    vector<pair<int,int>> e(m);
    for(int i=0;i<m;i++){
        int x,y;
        cin>>x>>y;
        e[i]={x,y};
    }
    for(int i=1;i<=m;i++){
        auto [x,y]=e[i-1];
        pre[i]=pre[i-1];
        pre[i].unionn(x,y);
    }
    for(int i=m;i;i--){
        auto [x,y]=e[i-1];
        suf[i]=suf[i+1];
        suf[i].unionn(x,y);
    }
    int q;
    cin>>q;
    while(q--){
        int l,r;
        cin>>l>>r;
        auto u=pre[l-1],v=suf[r+1];
        for(int i=1;i<=n;i++){
            u.unionn(i,v.findd(i));
        }
        int ans=0;
        for(int i=1;i<=n;i++){
            if(u.p[i]==i){
                ans++;
            }
        }
        cout<<ans<<'\n';
    }
}

int main(){
    ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    //freopen("input.txt","r",stdin);
	//freopen("output.txt","w",stdout);
    int T=1;
    //cin>>T;
    while(T--){
        solve();
    }
    return 0;
}
posted @   fengxue-K  阅读(14)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示