CF-292D Connected Components 並查集 好題

D. Connected Components

題意

如今有n個點,m條編號爲1-m的無向邊,給出k個詢問,每一個詢問給出區間[l,r],讓輸出刪除標號爲l-r的邊後還有幾個連通塊?c++

思路

去除編號爲[l,r]的邊後,只剩下了[1,l-1]&&[r+1,m]兩部分。spa

咱們維護一個前綴以及後綴並查集,詢問的時候把這兩部分的邊合併一下,就能夠求出連通塊的個數。code

精闢!component

代碼

#include<bits/stdc++.h>
#include<vector>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<string>
#include<math.h>
#include<queue>
#include<map>
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=1e4+10;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;

int n,m,k;
struct dsu
{
    int fa[510],num;
    void init()
    {
        num=n;
        for(int i=1;i<=n;i++)
            fa[i]=i;
    }
    int find(int x)
    {
        if(fa[x]==x) return x;
        return fa[x]=find(fa[x]);
    }
    void join(int u,int v)
    {
        u=find(u);
        v=find(v);
        if(u==v) return;
        fa[u]=v;
        num--;
    }
}pre[N],suf[N];
struct note
{
    int u,v;
}arr[N];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
        scanf("%d%d",&arr[i].u,&arr[i].v);
    pre[0].init();
    for(int i=1;i<=m;i++)
    {
        pre[i]=pre[i-1];
        pre[i].join(arr[i].u,arr[i].v);
    }
    suf[m+1].init();
    for(int i=m;i>=0;i--)
    {
        suf[i]=suf[i+1];
        suf[i].join(arr[i].u,arr[i].v);
    }
    scanf("%d",&k);
    while(k--)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        dsu tmp=pre[l-1];
        for(int i=1;i<=n;i++)//把同一個點在兩部分中的祖先合併
            tmp.join(tmp.find(i),suf[r+1].find(i));
        printf("%d\n",tmp.num);
    }
    return 0;
}
/*
*/

博客get

相關文章
相關標籤/搜索