CodeForces 292D Connected Components(并查集 前后缀)

来源:互联网 发布:阿芙护肤品怎么样知乎 编辑:程序博客网 时间:2024/04/30 12:05

题意:给你n个点,m条边,现在q次询问,每次询问给你一个l, r, 问你删除第l至r条边后,连通块的数量。(每次询问

后又把所有边加上) n < 100, m < 1e4, q < 2e4


思路:想着暴力或是对询问区间进行排序再去操作,复杂度都很高,显然不行。每次询问是把一段区间的边删去,所

我们可以预处理出 1~i 和 j~m 条边构成的并查集,这样空间复杂度1e4*100,可以满足,每次询问,合并一下1~l-1

r+1~m这两个并查集,就能求得答案。


代码:

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxn = 5e2+5;const int maxm = 1e4+5;int preL[maxm][maxn], preR[maxm][maxn], preTmp[maxn];int u[maxm], v[maxm], n, m;int Find(int *pre, int x){    int r = x;    while(pre[r] != r) r = pre[r];    int i = x, j;    while(i != r)    {        j = pre[i];        pre[i] = r;        i = j;    }    return r;}void join(int *pre, int x, int y){    int a = Find(pre, x);    int b = Find(pre, y);    if(a != b)        pre[b] = a;}void init(){    for(int i = 1; i <= n; i++)            preL[0][i] = preR[0][i] = preL[m+1][i] = preR[m+1][i] = i;    for(int i = 1; i <= m; i++)    {        for(int j = 1; j <= n; j++) preL[i][j] = preL[i-1][j];        join(preL[i], u[i], v[i]);    }    for(int i = m; i >= 1; i--)    {        for(int j = 1; j <= n; j++) preR[i][j] = preR[i+1][j];        join(preR[i], u[i], v[i]);    }}int cal(int l, int r){    for(int i = 1; i <= n; i++)        preTmp[i] = preL[l-1][i];    for(int i = 1; i <= n; i++)        join(preTmp, preL[l-1][i], preR[r+1][i]);    int ans = 0;    for(int i = 1; i <= n; i++)        if(i == Find(preTmp, i))            ans++;    return ans;}int main(void){    while(cin >> n >> m)    {        for(int i = 1; i <= m; i++)            scanf("%d%d", &u[i], &v[i]);        init();        int q;        scanf("%d", &q);        while(q--)        {            int l, r;            scanf("%d%d", &l, &r);            printf("%d\n", cal(l, r));        }    }    return 0;}


原创粉丝点击