jzoj 3453_连通块_并查集

来源:互联网 发布:手机剪辑视频软件 编辑:程序博客网 时间:2024/05/20 20:57

题目描述

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

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

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


思路

两个并查集,f[i]表示前i条边所连成的点的集合,g[j]表示后j条边所连成的点的集合。 那么对于一个询问 [l,r],我们就可以通过合并f[l-1]和g[r+1]两个集合来确定有几个联通块


#include <stdio.h>#include <cstring>using namespace std;int n, m;#define fill(x, y) memset(x, y, sizeof(x))int f[10005][501], g[10005][501], a[10001][3], fl[501];__attribute__((optimize("-O2")))inline int find(int x, int t){    //if (t > m || t < 1) return 0;    if (!f[t][x]) return x;    f[t][x] = find(f[t][x], t);    return f[t][x];}__attribute__((optimize("-O2")))inline int insert(int x, int y, int t){    if (find(x, t) != find(y, t))    {        f[t][find(x, t)] = find(y, t);        return 0;    }    return 0;}__attribute__((optimize("-O2")))inline int find1(int x, int t){    //if (t > m || t < 1) return 0;    if (!g[t][x]) return x;    g[t][x] = find1(g[t][x], t);    return g[t][x];}__attribute__((optimize("-O2")))inline int insert1(int x, int y, int t){    //int xx = find1(x, t), yy = find1(y, t);    if (find1(x, t) != find1(y, t))    {        g[t][find1(x, t)] = find1(y, t);        return 0;    }    return 0;}__attribute__((optimize("-O2")))inline int find2(int x){    if (!fl[x]) return x;    fl[x] = find2(fl[x]);    return fl[x];}__attribute__((optimize("-O2")))inline int insert2(int x, int y, int r){    int xx = find2(x), yy = find2(y);    if (xx != yy)    {        fl[xx] = yy;        return 0;    }    return 0;}int main(){    freopen("connect.in","r",stdin);    freopen("connect.out","w",stdout);    scanf("%d%d", &n, &m);    for (int i = 1; i <= m; i++)    {        int x, y;        scanf("%d%d", &x, &y);        a[i][1] = x; a[i][2] = y;        for (int j = 1; j <= n; j++)        {            f[i][j] = f[i - 1][j];        }        insert(x, y, i);    }    for (int i = m; i >= 1; i--)    {        int x = a[i][1], y = a[i][2];        for (int j = 1; j <= n; j++)        {            g[i][j] = g[i + 1][j];        }        insert1(x, y, i);    }    int t;    scanf("%d", &t);    for (int i = 1; i <= t; i++)    {        int l, r;        scanf("%d%d", &l, &r);        int ans = 0;        for (int j = 1; j <= n; j++)            fl[j] = f[l - 1][j];        for (int j = 1; j <= n; j++)        {            if (find2(j) != find1(j , r + 1))            {                insert2(find2(j), find1(j ,r + 1), r + 1);            }           }        for (int j = 1; j <= n; j++)            if (fl[j] == 0) ans++;        printf("%d\n", ans);    }}
原创粉丝点击