zoukankan      html  css  js  c++  java
  • 「HNOI2012」三角形覆盖问题

    传送门

    说真的这题的做法很迷啊,大部分做法都是 (O(n^2)) 级别过的。

    我也不例外

    不过 (O(n ^ 2)) 的做法确实很容易懂。

    考虑扫描线,我们把所有三角形按底边的 (y) 值排序,然后从下往上扫,每次只移动一个单位长度。

    然后我们在这个狭长的矩形里面截出来的面积就一定是若干梯形的面积之和,那么我们只要知道扫描线移动前后的有效长度,也就是上底下底,就可以算出该部分的贡献。

    然后考虑怎么加入或删除一个三角形的贡献:考虑到一个三角形只会加入和删除一次,用双向链表,每次把当前扫到的三角形加进来,往上移动扫描线的时候把当前链表中的三角形都砍掉最下面一行,判一下该三角形还存不存在,不存在了就删掉。

    加入和删除的过程维护一下每个横坐标被覆盖的次数,然后更新扫描线长度即可。

    参考代码:

    #include <algorithm>
    #include <cstdio>
    using namespace std;
    
    template < class T > void read(T& s) {
        s = 0; int f = 0; char c = getchar();
        while ('0' > c || c > '9') f |= c == '-', c = getchar();
        while ('0' <= c && c <= '9') s = s * 10 + c - 48, c = getchar();
        s = f ? -s : s;
    }
    
    const int _ = 1e4 + 5, __ = 1e6 + 5;
    
    int n, mx, vis[__], hd, tl, pre[_], nxt[_]; struct node { int x, y, d, l, r; } t[_];
    int cmp(node a, node b) { return a.y < b.y; }
    
    void del(int x) { pre[nxt[x]] = pre[x], nxt[pre[x]] = nxt[x]; }
    
    int check(int u) {
        if (!t[u].d) return 0;
        for (int i = nxt[hd]; i != tl; i = nxt[i])
            if (t[i].l <= t[u].l && t[u].r <= t[i].r) return 0;
        pre[nxt[hd]] = u, nxt[u] = nxt[hd], nxt[hd] = u, pre[u] = hd;
        return 1;
    }
    
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("cpp.in", "r", stdin), freopen("cpp.out", "w", stdout);
    #endif
        read(n);
        for (int x, y, d, i = 1; i <= n; ++i)
            read(x), read(y), read(d), t[i] = (node) { x, y, d, x, x + d - 1 }, mx = max(mx, y + d);
        sort(t + 1, t + n + 1, cmp);
        hd = 0, tl = n + 1, nxt[hd] = tl, pre[tl] = hd;
        int now = 0, last = 0, ans = 0;
        for (int i = t[1].y, j = 1; i <= mx; ++i) {
            now = last;
            for (int x = nxt[hd]; x != tl; x = nxt[x]) {
                if (!--vis[t[x].r]) --now;
                if ((--t[x].r) < t[x].l) del(x);
            }
            ans += now + last;
            for (; j <= n && t[j].y == i; ++j)
                if (check(j))
                    for (int x = t[j].l; x <= t[j].r; ++x)
                        if (!vis[x]++) ++now;
            last = now;
        }
        printf("%.1lf
    ", ans / 2.0);
        return 0;
    }
    
    
  • 相关阅读:
    Xcode一些好用的插件,以及这些插件的管理器
    iOS证书说明和发布
    iOS开发—音乐的播放
    POJ 1287 Networking 【最小生成树Kruskal】
    HDU1233 还是畅通工程【最小生成树】
    POJ 1251 + HDU 1301 Jungle Roads 【最小生成树】
    128 编辑器 【双栈】
    154. 滑动窗口【单调队列】
    5. 多重背包问题 II 【用二进制优化】
    4. 多重背包问题 I
  • 原文地址:https://www.cnblogs.com/zsbzsb/p/13149440.html
Copyright © 2011-2022 走看看