TIOJ-1129

聚集問題

https://tioj.ck.tp.edu.tw/problems/1129

Description

給定二維平面上$N$個點,若編號$i,j$的點之間的距離不大於$C$則他們之間有連邊
問最後的連通塊數量以及每個連通塊的大小

Solution

我想不到比$\mathcal{O}(N^2)$枚舉直接連邊更好的解了XD
比起DFS我更喜歡用DSU因此code是DSU

AC code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <cstdio>
#include <algorithm>
#include <vector>

const int N = 4001;
int s, n, r;
std::pair<int,int> p[N];
int pa[N], sz[N];
std::vector<int> ans;
int dis(std::pair<int,int> a, std::pair<int,int> b) {return (a.first-b.first)*(a.first-b.first) + (a.second-b.second)*(a.second-b.second);}
int anc(int x) {return x==pa[x]?x:pa[x]=anc(pa[x]);}
void uni(int x, int y) {
    if((x=anc(x)) == (y=anc(y))) return;
    if(sz[x] < sz[y]) s=x, x=y, y=s;
    pa[y] = x, sz[x] += sz[y];
}
signed main() {
    while(~scanf("%d%d%d", &s, &n, &r)) {
        p[0] = {s, s};
        for(int i = 1; i <= n; i++) {
            p[i].first = (p[i-1].first*269+11)%103;
            p[i].second = (p[i-1].second*271+13)%97;
            pa[i] = i, sz[i] = 1;
        }
        sort(p+1, p+n+1);
        for(int i = 1; i <= n; i++) {
            for(int j = i+1; j <= n; j++) {
                if(p[j].first - p[i].first > r) break;
                if(dis(p[i],p[j]) <= r*r)
                    uni(i, j);
            }
        }
        ans.clear();
        for(int i = 1; i <= n; i++) if(pa[i] == i) ans.emplace_back(sz[i]);
        std::sort(ans.begin(), ans.end());
        printf("%d\n", int(ans.size()));
        for(int x: ans) printf("%d ", x);
        puts("");
    }
}
comments powered by Disqus