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 <bits/stdc++.h>
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<int> 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;
}