• 2018 徐州赛区网赛 G. Trace


    题目链接在这里

    题意是:按时间先后有许多左下角固定为(0,0),右上角为(xi,yi)的矩形浪潮,每次浪潮会留下痕迹,但是后来的浪潮又会冲刷掉自己区域的老痕,留下新痕迹,问最后留下的痕迹长度为多少?

    这题里,不存在2个浪潮,使得一个浪潮完全被另一个覆盖.

    如图,经过了(1,4),(4,1),(3,3)浪潮后,所留下的痕迹(红边为10).

        每次浪潮都会有贡献.再而,如果浪潮在时间上从前往后考虑,则不能知悉当前浪潮会被以后的多少浪潮影响.所以从后往前考虑,可以把握每次浪潮带给当前浪潮的影响.

        其次,时间上从后往前考虑,对于当前浪潮在x方向的贡献,必然是没有被前面所考虑的(时间上在后面的)的浪潮所覆盖的部分.那么什么样的浪潮会覆盖掉自己的x边?比自己高的浪都会覆盖自己的x边,覆盖被覆盖的最多的,也就是>y的那些浪中,x最大的那个.

    总结一下:对于当前的浪(xi,yi),xi边的贡献是xi-x,其中x是>yi的浪中,x坐标最大的浪.

    yi边的贡献是yi-y,其中y是>xi的浪中,y最大的浪.

    为什么不是>= ? 因为如果有两个浪的x或者y相同的话,必然有一个浪被包含于另外一个浪中,这不符合题意.

    问题演变成区间查询和点更新,线段树解决即可:

    #include <bits/stdc++.h>
    using namespace std;
    
    #define ll long long
    #define FOR(i,a,b) for(int i=(a);i<=(b);++i)
    #define DOR(i,a,b) for(int i=(a);i>=(b);--i) 
    const int maxN=1e6+5;
    
    int N, M, K, T;
    int le[maxN], ri[maxN], A[maxN];
    int gx[maxN<<2], gy[maxN<<2];
    
    #define lson l,m,rt*2
    #define rson m+1,r,rt*2+1
    
    void update(int op, int p, int c, int l, int r, int rt) {
        if (l == r) {
            if (op == 1) gx[rt] = max(c, gx[rt]);
            else gy[rt] = max(c, gy[rt]);
            return;
        }
        int m = (l + r) / 2;
        int lch = rt * 2, rch = lch + 1;
        if (p <= m) update(op, p, c, lson);
        else update(op, p, c, rson);
        // push_up 
        if (op == 1) gx[rt] = max(gx[lch], gx[rch]);
        else gy[rt] = max(gy[lch], gy[rch]);
    }
    int query(int op, int L, int R, int l, int r, int rt) {
        if (L <= l && r <= R) {
            if (op == 1) return gx[rt];
            else return gy[rt];
        }
        int m = (l + r) / 2;
        int ans = 0;
        if (L <= m) ans = max(ans, query(op, L, R, lson));
        if (R > m) ans = max(ans, query(op, L, R, rson));
        return ans;
    }
    
    int main () {
        scanf("%d", &N);
        int k = 0;
        FOR(i, 1, N) {
            scanf("%d%d", &le[i], &ri[i]);
            A[k++] = le[i], A[k++] = ri[i];
        }
        sort(A, A + k);
        k = unique(A, A + k) - A;
    
        // Build Segment Tree
        memset(gx, 0, sizeof gx);
        memset(gy, 0, sizeof gy);
    
        ll ans = 0;
        DOR(i, N, 1) {
            int a = le[i], b = ri[i];
            le[i] = lower_bound(A, A + k, le[i]) - A + 1;
            ri[i] = lower_bound(A, A + k, ri[i]) - A + 1;
    
            int my = query(1, le[i], k, 1, k, 1);
            int mx = query(2, ri[i], k, 1, k, 1);
            ans += (b - my) + (a - mx);
    
            update(1, le[i], A[ri[i] - 1], 1, k, 1);
            update(2, ri[i], A[le[i] - 1], 1, k, 1);
        }
        printf("%lld
    ", ans);
        return 0;
    }
  • 相关阅读:
    细数阿里云在使用 Docker 过程中踩过的那些坑
    细数阿里云在使用 Docker 过程中踩过的那些坑
    javascript – 从页面停用浏览器打印选项(页眉,页脚,页边距)?
    jquery children()方法
    jquery 获取输入框的值
    java BigDecimal加减乘除
    window.print()打印时,如何自定义页眉/页脚、页边距
    深入分析:12C ASM Normal冗余中PDB文件块号与AU关系与恢复
    我不是药神,救不了你的穷根
    Install fail! Error: EPERM: operation not permitted
  • 原文地址:https://www.cnblogs.com/Rosebud/p/9615252.html
Copyright © 2020-2023  润新知