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\n", ans);
    return 0;
}

 

posted @ 2018-09-09 21:38  gaawing  阅读(261)  评论(0编辑  收藏  举报