【Henu ACM Round#24 E】Connected Components

【链接】 我是链接,点我呀:)
【题意】

在这里输入题意

【题解】

要求把连续的一段li..ri的边全都删掉。 然后求剩下的图的联通数

如果暴力的话
复杂度显然是O(k*m)级别的。

考虑我们把li..ri全都删掉。
接下来要做两件事。
第一是把1..li-1这些边连起来。
并查集1

然后是把ri+1..m这些边连起来。
并查集2

然后把并查集1和并查集2合并在一起求联通分量就好

两个并查集合在一起可以在线性复杂度内完成。

那么花费的时间就在1..li-1和ri+1,,m这两个并查集的获取上。
注意到n非常小。
我们可以处理出来前i条边的前缀并查集。
和i..m这些边的后缀并查集。
这样这两个并查集就能在O(1)下获取了。

然后合并两个并查集就好。
复杂度是O(n*m)
足以通过了。

【代码】

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

const int M = 1e4;
const int N = 500;

struct BCJ{
    int f[N+10],n;

    void Init(int nn){
        n = nn;
        for (int i = 1;i <= n;i++) f[i] = i;
    }

    int ff(int x){
        if (f[x]==x) return x;
        else return f[x] = ff(f[x]);
    }

    void join(int x,int y){
        int r1 = ff(x),r2 = ff(y);
        if (r1!=r2) f[r1] = r2;
    }

    int Get_Union(){
        int cnt = 0;
        for (int i = 1;i <= n;i++)
            if (ff(i)==i){
                cnt++;
            }
        return cnt;
    }

}pre[M+10],last[M+10];

pair<int,int> a[M+10];
int n,m;

int solve(BCJ a,BCJ b){
    for (int i = 1;i <= n;i++) b.join(a.ff(i),i);
    return b.Get_Union();
}

int main()
{
    cin >> n >> m;
    for (int i = 1;i <= m;i++) cin >> a[i].first >> a[i].second;
    pre[0].Init(n);
    for (int i = 1;i <= m;i++){
        pre[i] = pre[i-1];
        pre[i].join(a[i].first,a[i].second);
    }

    last[m+1].Init(n);
    for (int i = m;i >= 1;i--){
        last[i] = last[i+1];
        last[i].join(a[i].first,a[i].second);
    }

    int k;
    cin >> k;
    for (int i = 1;i <= k;i++){
        int x,y;
        cin >> x >> y;
        cout<<solve(pre[x-1],last[y+1])<<endl;
    }
    return 0;
}


posted @ 2018-04-18 08:54  AWCXV  阅读(141)  评论(0编辑  收藏  举报