3453. 【NOIP2013中秋节模拟】连通块

Description

你应该知道无向图的连通块的数量,你应该知道如何求连通块的数量。当你兴奋与你的成就时,破坏王Alice拆掉了图中的边。当她发现,每删去一条边,你都会记下边的编号,同时告诉她当前连通块的个数。

然而,对边编号简直就是个悲剧,因为Alice为了刁难你,拆掉编号从l到r的边,当然你需要做的事情就是求连通块的个数。如果你答对了,Alice会把拆掉的边装好,迚行下一次破坏。如果你无法完成这个任务,Alice会彻底毁了你的图。

进行完足够多次之后,Alice觉得无聊,就玩去了,而你却需要继续做第三题。

Input

第一行两个整数n,m,表示点数和边数。

之后m行每行两个整数x,y,表示x与y之间有无向边。(按读入顺序给边编号,编号从1开始)

一行一个整数k,表示Alice的破坏次数。

之后k行,每行两个整数l,r。

Output

k行,每行一个整数。

Sample Input

6 5

1 2

5 4

2 3

3 1

3 6

6

1 3

2 5

1 5

5 5

2 4

3 3

Sample Output

4

5

6

3

4

2

Data Constraint

对于30%的数据,n<=100,k<=10

对于60%的数据,k<=1000

对于100%的数据,n<=500,m<=10000,k<=20000,1<=l<=r<=m

Solution

connect:并查集。每一个f[i]为一个并查集,记录只添加前i条边时,所有节点的联通情况。每一个g[i]也是一个并查集,记录只添加i—m条边时,所有节点的联通情况。对于每个询问只要把f[l-1]和g[r+1]合并即可。
合并只需判断f中i的祖先是否和g中i的祖先在h(h为合并的数组)中联通,如果不连通则将他们连起来。

Code1

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 520
#define M 10010
using namespace std;
int n,m,k,l,r,ans=0,f[M][N],g[M][N],x[M],y[M],h[M];
int getf(int x,int k){
    if(f[k][x]==x) return x;
    return f[k][x]=getf(f[k][x],k);
}
int getg(int x,int k){
    if(g[k][x]==x) return x;
    return g[k][x]=getg(g[k][x],k);
}
int geth(int x){
    if(h[x]==x) return x;
    return h[x]=geth(h[x]);
}
int main(){
    freopen("connect.in","r",stdin);
    freopen("connect.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) f[0][i]=g[m+1][i]=i;
    for(int i=1;i<=m;i++){
        for(int j=1;j<=n;j++) f[i][j]=f[i-1][j];
        scanf("%d%d",&x[i],&y[i]);
        int fx=getf(x[i],i),fy=getf(y[i],i);
        if(fx!=fy) f[i][fx]=f[i][fy];
    }
    for(int i=m;i>=1;i--){
        for(int j=1;j<=n;j++) g[i][j]=g[i+1][j];
        int fx=getg(x[i],i),fy=getg(y[i],i);
        if(fx!=fy) g[i][fx]=g[i][fy];
    }
    scanf("%d",&k);
    for(int i=1;i<=k;i++){
        scanf("%d%d",&l,&r);
        for(int j=1;j<=n;j++) h[j]=f[l-1][j];
        for(int j=1;j<=n;j++){
            int fx=geth(j),fy=geth(getg(j,r+1));
            if(fx!=fy) h[fx]=fy;
        }
        ans=0;
        for(int j=1;j<=n;j++) if(h[j]==j) ans++;
        printf("%d\n",ans);
    }
    return 0;
}

Code2

#pragma GCC optimize(3)
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<list>
#include<queue>
#include<stack>
#include<bitset>
#include<deque>
using namespace std;
#define ll long long
#define ri register int
#define il inline
#define fi first
#define se second
#define mp make_pair
#define pi pair<int,int>
#define mem0(x) memset((x),0,sizeof (x))
#define mem1(x) memset((x),0x3f,sizeof (x))
il char gc() {
    static const int BS = 1 << 22;
    static unsigned char buf[BS], *st, *ed;
    if (st == ed) ed = buf + fread(st = buf, 1, BS, stdin);
    return st == ed ? EOF : *st++;
}
#define gc getchar
template<class T>void in(T &x) {
    x = 0;
    bool f = 0;
    char c = gc();
    while (c < '0' || c > '9') {
        if (c == '-') f = 1;
        c = gc();
    }
    while ('0' <= c && c <= '9') {
        x = (x << 3) + (x << 1) + (c ^ 48);
        c = gc();
    }
    if (f) x = -x;
}
#undef gc
#define pb push_back
#define N 510
#define M 20010
int v[M], u[M];
int n, m;
int find(int x, int k[]) {
    return k[x] == x ? x : k[x] = find(k[x], k);
}
int f[10002][502], cntf;
int mpf[10002];
int g[10003][502], cntg;
int mpg[10002];
map< pi, int>rem;
int tmp[502];
signed main() {
#ifndef ONLINE_JUDGE
#endif
    freopen("connect.in", "r", stdin);
    freopen("connect.out", "w", stdout);
    in(n), in(m);
    for (ri i = 1, a, b; i <= m; ++i) {
        in(a), in(b);
        u[i] = a, v[i] = b;
    }
    for (ri i = 1; i <= n; ++i) g[0][i] = f[0][i] = i;
    g[0][0] = f[0][0] = n;
    for (ri i = 1, fx, fy; i <= m; ++i) {
        fx = find(u[i], f[cntf]), fy = find(v[i], f[cntf]);
        if (fx == fy) {
            mpf[i] = cntf;
            continue;
        }
        ++cntf;
        for (ri j = 1, lst = cntf - 1; j <= n; ++j) f[cntf][j] = f[lst][j];
        f[cntf][fy] = fx;
        f[cntf][0] = f[cntf - 1][0] - 1;
        mpf[i] = cntf;
    }
    for (ri i = m, fx, fy; i >= 1; --i) {
        fx = find(u[i], g[cntg]), fy = find(v[i], g[cntg]);
        if (fx == fy) {
            mpg[i] = cntg;
            continue;
        }
        ++cntg;
        for (ri j = 1, lst = cntg - 1; j <= n; ++j) g[cntg][j] = g[lst][j];
        g[cntg][fy] = fx;
        g[cntg][0] = g[cntg - 1][0] - 1;
        mpg[i] = cntg;
    }
    int q, l, r, lst, ans, tag;
    in(q);
    while (q--) {
        in(l), in(r);
        if (rem.count(mp(mpf[l - 1], mpg[r + 1]))) {
            printf("%d\n", rem[mp(mpf[l - 1], mpg[r + 1])]);
            continue;
        }
        if (r == m) {
            printf("%d\n", f[mpf[l - 1]][0]);
            continue;
        }
        if (l == 1) {
            printf("%d\n", g[mpg[r + 1]][0]);
            continue;
        }
        tag = mpf[l - 1];
        lst = mpg[r + 1];
        ans = f[tag][0];
        for (ri i = 1; i <= n; ++i) tmp[i] = f[tag][i];
        for (ri i = 1, fx, tx, ty; i <= n; ++i) {
            fx = find(i, g[lst]);
            if (fx != i) {
                tx = find(i, tmp), ty = find(fx, tmp);
                if (tx != ty) {
                    tmp[ty] = tx;
                    --ans;
                }
            }
        }
        rem[mp(tag, lst)] = ans;
        printf("%d\n", ans);
    }
    return 0;
}

作者:zsjzliziyang
QQ:1634151125
转载及修改请注明
本文地址:https://blog.csdn.net/zsjzliziyang/article/details/81807721

猜你喜欢

转载自blog.csdn.net/zsjzliziyang/article/details/81807721
今日推荐