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;
}

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