Edu73 F Choose a Square (线段树)

题意

在平面上有 \(n\) 个点, 已知每个点的 \((x, y)\) 及其权值 \(c\),现要求在直线 \(y = x\) 上选择正方形的左下角与右上角,使得正方形(含边界)所覆盖点的权值和 与 边长的差值最大,边长可为0,求最大差值并输出可行方案。

传送门

思路

既然正方形的一条对角线在 \(y = x\) 上,则可以在将点坐标离散化之后枚举右上角的坐标 \(y\) ,求 \([1, y]\) 范围内区间和 - 边长的最大值及其下标。

可以采用线段树维护差值的最大值及其下标。

线段树使用

  假设点的权值和为 \(sum\) , 正方形左下角坐标为 \((x, x)\) ,右上角坐标为\((y, y)\) ,则最终答案计算公式为 $ans = sum - (y-x) = sum + x - y $ 。

将所有点的坐标离散化之后,线段树的叶子结点初值赋值为对应的 \(x\) ,其余则为正常维护区间和的最大值及其下标,query出的最大值即为 \(sum+x\) ,减去所枚举的 \(y\) 即为对应 \(ans\)

Code

#include 

using namespace std;

typedef long long ll;
const int maxn = 1e6+10;

int n;
int hsy[maxn<<1], pn;
int x[maxn], y[maxn], c[maxn];
ll mx, pos;
vector g[maxn<<1];

struct node {
    int l, r, pos; ll mx, lazy;
}tr[maxn<<2];

#define lson i<<1
#define rson i<<1|1

void pushup(int i) {
    if(tr[lson].mx > tr[rson].mx) tr[i].mx = tr[lson].mx, tr[i].pos = tr[lson].pos;
    else tr[i].mx = tr[rson].mx, tr[i].pos = tr[rson].pos;
}

void pushdown(int i) {
    if(!tr[i].lazy) return;
    tr[lson].mx += tr[i].lazy;
    tr[lson].lazy += tr[i].lazy;
    tr[rson].mx += tr[i].lazy;
    tr[rson].lazy += tr[i].lazy;
    tr[i].lazy = 0;
}

void build(int l, int r, int i) {
    tr[i] = node{l, r, l, 0, 0};
    if(l == r) {
        tr[i].mx = hsy[l];
        tr[i].pos = l;
        return;
    }
    int mid = l+r >> 1;
    build(l, mid, lson);
    build(mid+1, r, rson);
    pushup(i);
}

void update(int l, int r, ll val, int i) {
    if(l <= tr[i].l && tr[i].r <=r ) {
        tr[i].mx += val;
        tr[i].lazy += val;
        return;
    }
    pushdown(i);
    int mid = tr[i].l+tr[i].r >> 1;
    if(l <= mid) update(l, r, val, lson);
    if(mid < r) update(l, r, val, rson);
    pushup(i);
}

void query(int l, int r, int i) {
    if(l <= tr[i].l && tr[i].r <= r) {
        if(tr[i].mx > mx) {
            mx = tr[i].mx;
            pos = tr[i].pos;
        }
        return;
    }
    pushdown(i);
    int mid = tr[i].l+tr[i].r>>1;
    if(l <= mid) query(l, r, lson);
    if(r > mid) query(l, r, rson);
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {
        scanf("%d%d%d", x+i, y+i, c+i);
        if(x[i] > y[i]) swap(x[i], y[i]);
        hsy[++pn] = x[i];
        hsy[++pn] = y[i];
    }
    sort(hsy+1, hsy+1+pn);
    pn = unique(hsy+1, hsy+1+pn) - hsy-1;

    build(1, pn, 1);
    for (int i = 1; i <= n; ++i) {
        x[i] = lower_bound(hsy+1, hsy+1+pn, x[i]) - hsy;
        y[i] = lower_bound(hsy+1, hsy+1+pn, y[i]) - hsy;
        g[y[i]].emplace_back(i);
    }

    ll ans = 0, ansx = 2e9, ansy = 2e9;

    for (int i = 1; i <= pn; ++i) {
        for (auto v: g[i])
            update(1, x[v], c[v], 1);
        mx = pos = 0;
        query(1, i, 1);
        mx -= hsy[i];
        if(mx > ans) {
            ans = mx;
            ansx = hsy[pos];
            ansy = hsy[i];
        }
    }
    printf("%lld\n%lld %lld %lld %lld\n", ans, ansx, ansx, ansy, ansy);
    return 0;
}

你可能感兴趣的:(Edu73 F Choose a Square (线段树))