题目链接https://codeforc.es/problemset/problem/1221/F
题意
二维平面内有n个带权值的点,要求出一个两点在直线 y = x y=x y=x上的正方形,使得覆盖点的权值之和减去正方形的边长最大。
题解
假设正方形的坐标为
(
a
x
,
a
x
)
(ax,ax)
(ax,ax),
(
a
y
,
a
y
)
(ay,ay)
(ay,ay),如果点
(
x
,
y
)
(x,y)
(x,y)在正方形内,那么
a
x
<
=
m
i
n
(
x
,
y
)
ax<=min(x,y)
ax<=min(x,y)并且
m
a
x
(
x
,
y
)
<
=
a
y
max(x,y)<=ay
max(x,y)<=ay。
这样考虑的话每个点就转化成一个区间,现在是要求一段大区间使得包含的小区间权值之和减去大区间长度最大。
很显然答案一定是在小区间端点上的,所以把小区间按照右端点排个序,枚举右端点,把每个区间的权值在线段树上更新,线段树上维护最大值和位置就行了。
线段树初始可以给每个点赋一个递增的负值,这样就能维护长度的答案了。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double db;
typedef pair<ll,int>piir;
const int N=2e6+7;
const ll inf=1e18;
int n;
ll lz[N<<2];
piir t[N<<2];
int b[N],tot;
int ax,ay;
ll ans;
struct Node{
int x,y,c;
bool operator<(const Node k)const{return y<k.y;}
}a[N];
void bd(int rt,int l,int r){
lz[rt]=0;
if(l==r){
t[rt].first=b[l]-b[tot];
t[rt].second=l;
return;
}
int m=l+r>>1;
bd(rt<<1,l,m);
bd(rt<<1|1,m+1,r);
if(t[rt<<1].first>t[rt<<1|1].first) t[rt]=t[rt<<1];
else t[rt]=t[rt<<1|1];
}
void pd(int rt){
if(lz[rt]){
t[rt<<1].first+=lz[rt];
t[rt<<1|1].first+=lz[rt];
lz[rt<<1]+=lz[rt];
lz[rt<<1|1]+=lz[rt];
lz[rt]=0;
}
}
void upd(int rt,int l,int r,int L,int R,ll val){
if(L<=l&&r<=R){t[rt].first+=val;lz[rt]+=val;return;}
pd(rt);
int m=l+r>>1;
if(L<=m) upd(rt<<1,l,m,L,R,val);
if(m<R) upd(rt<<1|1,m+1,r,L,R,val);
if(t[rt<<1].first>t[rt<<1|1].first) t[rt]=t[rt<<1];
else t[rt]=t[rt<<1|1];
}
piir que(int rt,int l,int r,int L,int R){
if(L<=l&&r<=R) return t[rt];
pd(rt);
int m=l+r>>1;
piir le=piir(-inf,0),ri=piir(-inf,0);
if(L<=m) le=que(rt<<1,l,m,L,R);
if(m<R) ri=que(rt<<1|1,m+1,r,L,R);
return (le.first>ri.first)?le:ri;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].c);
if(a[i].x>a[i].y) swap(a[i].x,a[i].y);
b[++tot]=a[i].x;
b[++tot]=a[i].y;
}
sort(b+1,b+1+tot);
tot=unique(b+1,b+1+tot)-b-1;
for(int i=1;i<=n;i++){
a[i].x=lower_bound(b+1,b+1+tot,a[i].x)-b;
a[i].y=lower_bound(b+1,b+1+tot,a[i].y)-b;
}
bd(1,1,tot);
sort(a+1,a+1+n);
for(int i=1;i<=n;i++){
upd(1,1,tot,1,a[i].x,a[i].c);
if(i<n&&a[i+1].y==a[i].y) continue;
piir tmp=que(1,1,tot,1,a[i].y);
if(tmp.first+b[tot]-b[a[i].y]>ans){
ans=tmp.first+b[tot]-b[a[i].y];
ax=tmp.second;
ay=a[i].y;
}
}
printf("%lld\n",ans);
b[tot+1]=-1;
if(ans==0){
for(int i=1;i<=tot;i++){
if(b[i]==b[i+1]) continue;
if(b[i]+1!=b[i+1]){
printf("%d %d %d %d\n",b[i]+1,b[i]+1,b[i]+1,b[i]+1);
break;
}
}
}
else printf("%d %d %d %d\n",b[ax],b[ax],b[ay],b[ay]);
}