1 条题解

  • 0
    @ 2026-5-3 7:33:04

    更好的阅读体验

    思路

    先从 subtask 9 入手,这个 sub 满足任意两点之间的距离不小于 r2\frac{r}{2}。感性理解一下,发现这种情况的边数是 Θ(n)\Theta(n) 量级的。

    考虑如何快速找到这些有效的边。想办法找到 r2\frac{r}{2} 的作用,将整个平面按 r2\frac{r}{2} 个单位长度分块,每一块为一个 r2×r2\frac{r}{2} \times \frac{r}{2} 的正方形区域。分块过后有一个很好的性质,每块内只有 Θ(1)\Theta(1) 个点,且这些点两两均有连边,同时每块内的点都只有可能与以其为中心的 5×55 \times 5 个块有连边。判断是否能以相反颜色跳回使用拓展域并查集即可。

    接下来思考满分做法。继续沿用上面的分块方法,注意到若一个块内存在 3\geq 3 个点,那么这些点显然可以只通过走块内的点获得一个可行的路径,所以对于这种块内的点的答案一定是 1,在并查集上可以直接连接 (i,¬i)(i,\neg i)。对于只存在 <3< 3 个点的块,采用 subtask 9 的方法暴力连边即可。

    这时候可以大胆猜测这样做复杂度就是 Θ(n)\Theta(n) 的,证明也比较容易。为了方便叙述,我们称 3\geq 3 个点的块为大块,<3< 3 个点的块为小块。那么对于每一个小块和大块都最多与 5×55 \times 5 个小块连边,所以显然连边的量级是 Θ(n)\Theta(n) 的(大约会有 5050 的常数)。

    Code

    #include <bits/stdc++.h>
    #define re register
    #define fst first
    #define snd second
    #define int long long
    
    using namespace std;
    
    typedef pair<int,int> pii;
    const int N = 2e5 + 10;
    int n,r;
    int fp[N];
    pii arr[N];
    map<pii,vector<int>> mp;
    
    inline int read(){
        int r = 0,w = 1;
        char c = getchar();
        while (c < '0' || c > '9'){
            if (c == '-') w = -1;
            c = getchar();
        }
        while (c >= '0' && c <= '9'){
            r = (r << 3) + (r << 1) + (c ^ 48);
            c = getchar();
        }
        return r * w;
    }
    
    inline int find(int x){
        if (fp[x] == x) return fp[x];
        else return fp[x] = find(fp[x]);
    }
    
    inline void merge(int a,int b){
        int x = find(a),y = find(b);
        if (x != y) fp[x] = y;
    }
    
    signed main(){
        n = read(),r = read();
        const int B = (r + 1) / 2;
        for (re int i = 1;i <= n * 2;i++) fp[i] = i;
        for (re int i = 1;i <= n;i++){
            arr[i].fst = read(),arr[i].snd = read();
            mp[{arr[i].fst / B,arr[i].snd / B}].push_back(i);
        }
        for (auto it = mp.begin();it != mp.end();it++){
            vector<int> v = (it -> snd);
            if (v.size() >= 3){
                for (int x:v) merge(x,x + n);
            }
            else{
                for (re int i = (it -> fst).fst - 2;i <= (it -> fst).fst + 2;i++){
                    for (re int j = (it -> fst).snd - 2;j <= (it -> fst).snd + 2;j++){
                        if (mp.count({i,j})){
                            for (int x:v){
                                for (int y:mp[{i,j}]){
                                    if (x != y && (arr[x].fst - arr[y].fst) * (arr[x].fst - arr[y].fst) + (arr[x].snd - arr[y].snd) * (arr[x].snd - arr[y].snd) <= r * r){
                                        merge(x,y + n); merge(x + n,y);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        for (re int i = 1;i <= n;i++) printf("%d",(find(i) == find(i + n)) ? 1 : 0);
        return 0;
    }
    
    • 1

    信息

    ID
    9584
    时间
    1000ms
    内存
    128MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者