ICPC Central Europe Regional Contest 2019 Saba1000kg(并查集暴力)

There are many different streams in Viking rock movement. Old Icelandic granite rock, Middle Danish dusty Viking rock, Late Finngail dark green rock, Fjord boulder avalanche rock, and many others, a complete list of all popular streams would overflow this page many times.

The Scandinavian Ministry of Higher Education studies various ways the streams influence each other. They are currently planning a huge experiment, when a number of suitably chosen volunteers will be distributed over an archipelago of uninhabited small islands, and the researchers want to observe the mutual influence of their rock styles and preferences over a relatively long period of time.

The inhabitants on one island will always influence each other. Some pairs of the islands are situated close enough for their inhabitants to influence each other, while the distances between other pairs prevent any direct influence. In the latter case, the inhabitants of such islands may still influence each other, but only indirectly, if there are one or more other islands that are inhabited and relay the influence.

There are several proposals on the distribution of the volunteers among the islands. For each of these distributions, the Ministry would like to know the number of independent groups of inhabitants that will form in the archipelago. Two groups of island inhabitants, each occupying one or more islands, are considered independent, if there is no possibility of their mutual influence, not even in the indirect way.

Help the Ministry to evaluate their proposals.

Input Specification

The first input line contains three integers, N, E, P (1 ≤ N ≤ 10^5, 0 ≤ E ≤ 10^5, 1 ≤ P ≤ 10^5)N,E,P(1≤N≤10
5
,0≤E≤10
5
,1≤P≤10
5
).

NN is the number of islands in the archipelago, EE is the number of pairs of islands that allow direct influence, and PP is the number of proposals to be evaluated. The islands are labeled from 11 to NN.

The next EE lines specify the pairs of islands that allow direct mutual influence. Each of these lines contains two integers AA and BB denoting the labels of two different islands. No pair of islands occurs more than once.

Each of the next PP lines describes one proposal. Each line starts with a number of islands inhabited under that proposal M (1 ≤ M ≤ N)M(1≤M≤N) and then contains pairwise distinct labels of MM inhabited islands. No other island will be inhabited under the respective proposal.

The sum of the sizes of all proposals (all numbers MM) does not exceed 10^510
5
.

Output Specification

For each proposal, print a line with the number of independent groups that will form in the archipelago.

输出时每行末尾的多余空格,不影响答案正确性

样例输入1复制
4 4 3
1 2
3 1
1 4
3 4
3 2 3 4
1 1
4 1 2 3 4
样例输出1复制
2
1
1
样例输入2复制
5 1 1
1 2
5 5 4 3 2 1
样例输出2复制
4

题意:
有n个点e条边。最多q次询问最多1e5个询问点,求对于每次询问给出的点构成了多少个连通块。

思路:
太妙了这题。

肯定能想到是并查集写,一开始写了暴力+几个剪枝怎么都过不了。
看了题解发现是,对于小于n\sqrt{n}的询问,直接m2m^2写(m是询问的点数)。对于大于n\sqrt{n}的询问,直接跑所有边。
最终复杂度为enlogne\sqrt{n}logn,和分块的思想异曲同工,将每次询问的均摊复杂度降低到了根号级别。

复杂度证明的话,不妨设m2m^2复杂度的询问总点数为aa, O(e)级别复杂度的总点数为bb

实际上就是将a拆成一些不大于sqrt(n)的数再取平方和,将b拆成一些大于sqrt(n)的数再将份数乘以e。

由于平方函数增长很快,肯定将a拆成sqrt(n)最优。对于b同样是拆成sqrt(n)最优。

所以最后的复杂度不超过enlogne\sqrt{n}logn

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <vector>
#include <cmath>

using namespace std;

typedef unsigned long long ull;

const int maxn = 1e5 + 7;
map<pair<int,int>,int>mp;
vector<int>G[maxn];
int n,e,p;
int fa[maxn];

int findset(int x) {
    if(fa[x] == x) return x;
    return fa[x] = findset(fa[x]);
}

void Union(int x,int y) {
    int rx = findset(x),ry = findset(y);
    if(rx != ry) {
        fa[rx] = ry;
    }
}

bool check(int x,int y) {
    int pos = lower_bound(G[x].begin(),G[x].end(),y) - G[x].begin();
    if(pos < G[x].size() && G[x][pos] == y) return true;
    return false;
}

int solve1(vector<int>&now,map<int,int>&flag) {
    for(int i = 0;i < now.size();i++) {
        int x = now[i];
        fa[x] = x;
    }
    
    int ans = 0;
    for(int i = 0;i < now.size();i++) {
        int x = now[i];
        for(int j = 0;j < G[x].size();j++) {
            int y = G[x][j];
            if(!flag[y]) continue;
            Union(x,y);
        }
    }
    
    for(int i = 0;i < now.size();i++) {
        int x = now[i];
        if(fa[x] == x) ans++;
    }
    return ans;
}

int solve2(vector<int>&now) {
    for(int i = 0;i < now.size();i++) {
        int x = now[i];
        fa[x] = x;
    }
    for(int i = 0;i < now.size();i++) {
        for(int j = i + 1;j < now.size();j++) {
            int x = now[i],y = now[j];
            if(check(x,y) || check(y,x)) {
                Union(x,y);
            }
        }
    }
    int ans = 0;
    for(int i = 0;i < now.size();i++) {
        int x = now[i];
        if(fa[x] == x) {
            ans++;
        }
    }
    return ans;
}

int main() {
    scanf("%d%d%d",&n,&e,&p);
    for(int i = 1;i <= e;i++) {
        int x,y;scanf("%d%d",&x,&y);
        G[x].push_back(y);
    }
    for(int i = 1;i <= n;i++) {
        sort(G[i].begin(),G[i].end());
    }
    int t = sqrt(n);
    for(int i = 1;i <= p;i++) {
        int m;scanf("%d",&m);
        vector<int>now;
        map<int,int>flag;
        for(int j = 1;j <= m;j++) {
            int x;scanf("%d",&x);
            now.push_back(x);
            flag[x] = 1;
        }
        if(m > t) {
            printf("%d\n",solve1(now,flag));
        }
        else {
            printf("%d\n",solve2(now));
        }
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章