1 条题解

  • 0
    @ 2025-8-24 22:16:21

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar zesqwq
    达标啦!耶 ⊙ω⊙

    搬运于2025-08-24 22:16:21,当前版本为作者最后更新于2022-11-18 07:26:32,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    P5998 [PA2014]Plemiona 题解

    Analysis

    很巧妙的东西,终于是胡出来了。

    首先,我们对矩形按照操作的 yy 值右端点排序。

    然后我们考虑用线段树维护 xx 轴。

    我们发现两个相交的线段所覆盖到的线段树节点上一定有某一对节点呈父子关系,原因显然。

    但是在线段树上一个节点的子树太大了,我们考虑用孩子数祖先。

    我们给每个线段树节点开 22vector,姑且叫它 vec1vec2

    我们把矩形加入线段树时就加入所有 访问过 的节点的 vec2,并且加入其完全覆盖的最上层节点(也就是我们平时线段树维护区间操作的那些节点)的 vec1

    我们合并矩形时时就计算与 访问过 的节点的 vec1 的矩形是否有交,并且计算其完全覆盖的最上层节点(也就是我们平时线段树维护区间操作的那些节点)的 vec2 是否有交。

    我们发现这个 vec1vec2 在排序之后符合单调性,即你可以从其末尾开始访问,但有一个不符合条件的时候就 break

    这个做法的正确性显然, 实际上这个做法的均摊时间复杂度是 O(nlogn)O(n \log n) 的,空间复杂度也一样,显然是可以通过的。

    最后贴一下代码。

    Code

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 4e5 + 10;
    int tab[N << 2], len, n;
    struct Square {
        int lx, ly, rx, ry;
        inline void read() {
            scanf("%d %d %d %d", &lx, &rx, &ly, &ry), ++lx, ++ly;
            tab[++len] = lx, tab[++len] = rx;
        }
        inline void print() { printf("%d %d %d %d\n", tab[lx] - 1, tab[rx], ly - 1, ry); }
        inline bool operator<(const Square &b) const { return ry < b.ry; }
        inline Square operator+(const Square &b) const { return {min(lx, b.lx), min(ly, b.ly), max(rx, b.rx), max(ry, b.ry)}; }
    } a[N];
    bool vis[N];
    inline bool calc(int x, int y) { return !((a[x].ly > a[y].ry) || (a[y].ly > a[x].ry)); }
    struct SegmentTree {
        vector<int> vec[N << 2], vec2[N << 2];  // vec 染色到矩形所有包含的线段上,vec2染色到所有有交该矩形的线段上。
        void update(int u, int L, int R, int l, int r, int v) {
            if (L > r || R < l) return;
            vec2[u].push_back(v);
            if (L >= l && R <= r) {
                vec[u].push_back(v);
                return;
            }
            int M = L + R >> 1;
            update(u << 1, L, M, l, r, v), update(u << 1 | 1, M + 1, R, l, r, v);
        }
        bool merge(int u, int L, int R, int l, int r, int v) {
            if (L > r || R < l) return 0;
            bool flag = 0;
            for (int i = vec[u].size() - 1; ~i; i = vec[u].size() - 1) {
                if (vis[vec[u][i]]) {
                    vec[u].pop_back();
                    continue;
                }
                if (!calc(vec[u][i], v)) break;
                a[v] = a[v] + a[vec[u][i]], vis[vec[u][i]] = 1;
                vec[u].pop_back();
                flag = 1;
            }
            if (L >= l && R <= r) {
                for (int i = vec2[u].size() - 1; ~i; i = vec2[u].size() - 1) {
                    if (vis[vec2[u][i]]) {
                        vec2[u].pop_back();
                        continue;
                    }
                    if (!calc(vec2[u][i], v)) break;
                    a[v] = a[v] + a[vec2[u][i]], vis[vec2[u][i]] = 1;
                    vec2[u].pop_back();
                    flag = 1;
                }
                return flag;
            }
            int M = L + R >> 1;
            return flag | merge(u << 1, L, M, l, r, v) | merge(u << 1 | 1, M + 1, R, l, r, v);
        }
    } seg;
    inline bool cmp(Square a, Square b) { return a.lx != b.lx ? a.lx < b.lx : (a.rx != b.rx ? a.rx < b.rx : (a.ly != b.ly ? a.ly < b.ly : a.ry < b.ry)); }
    int main() {
        cin >> n;
        for (int i = 1; i <= n; i++) a[i].read();
        sort(a + 1, a + n + 1), sort(tab + 1, tab + len + 1), len = unique(tab + 1, tab + len + 1) - tab - 1;
        for (int i = 1; i <= n; i++) {
            a[i].lx = lower_bound(tab + 1, tab + len + 1, a[i].lx) - tab;
            a[i].rx = lower_bound(tab + 1, tab + len + 1, a[i].rx) - tab;
        }
        for (int i = 1; i <= n; i++) {
            while (seg.merge(1, 1, len, a[i].lx, a[i].rx, i))
                ;
            seg.update(1, 1, len, a[i].lx, a[i].rx, i);
        }
        // for (int i = 1; i <= n; i++) --a[i].lx, --a[i].ly;
        int cnt = 0;
        for (int i = 1; i <= n; i++)
            if (!vis[i]) a[++cnt] = a[i];
        sort(a + 1, a + cnt + 1, cmp), cout << cnt << endl;
        for (int i = 1; i <= cnt; i++) a[i].print();
        return 0;
    }
    
    • 1

    信息

    ID
    5005
    时间
    1000ms
    内存
    125MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者