题意:
二维平面上有n个点,每个点上有权值,你可以选择一个矩形区域,使得这个矩形包括的点的权值和-矩形边长的值最大。矩形的右上角和左下角必须在x=y这条直线上。
题解:
一开始想的是dp,发现好像不行,然后一看这个左下右上的条件就知道是线段树了,首先离散化,然后枚举右上角,对于新增的点,用前缀和的方式增加到线段树上,然后增加的边长也用前缀和的方式增加到线段树上,最后查询最大值即可。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pa pair<int,ll>
const int N=1e6+5;
vector<pa>vec[N];
ll mx[N*4],f[N*4],c[N];
int x[N],y[N],b[N];
void push_down(int root){
if(!f[root])
return ;
mx[root<<1]+=f[root];
mx[root<<1|1]+=f[root];
f[root<<1]+=f[root];
f[root<<1|1]+=f[root];
f[root]=0;
}
void update(int l,int r,int root,int ql,int qr,ll v){
if(l>=ql&&r<=qr){
mx[root]+=v;
f[root]+=v;
return ;
}
push_down(root);
int mid=l+r>>1;
if(mid>=ql)
update(l,mid,root<<1,ql,qr,v);
if(mid<qr)
update(mid+1,r,root<<1|1,ql,qr,v);
mx[root]=max(mx[root<<1],mx[root<<1|1]);
}
int p;
ll query(int l,int r,int root,int ql,int qr){
if(l==r){
p=l;
return mx[root];
}
push_down(root);
int mid=l+r>>1;
if(mid>=ql&&mid<qr){
if(mx[root<<1]<mx[root<<1|1])
return query(mid+1,r,root<<1|1,ql,qr);
else
return query(l,mid,root<<1,ql,qr);
}
else if(mid>=ql)
return query(l,mid,root<<1,ql,qr);
else
return query(mid+1,r,root<<1|1,ql,qr);
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d%lld",&x[i],&y[i],&c[i]),b[i*2-1]=x[i],b[i*2]=y[i];
sort(b+1,b+1+n*2);
int all=unique(b+1,b+1+n*2)-b-1;
int x1=2e9,y1=2e9,x2=2e9,y2=2e9;
ll ans=0;
for(int i=1;i<=n;i++){
x[i]=lower_bound(b+1,b+1+all,x[i])-b;
y[i]=lower_bound(b+1,b+1+all,y[i])-b;
if(y[i]<x[i])
vec[x[i]].push_back({y[i],c[i]});
else
vec[y[i]].push_back({x[i],c[i]});
}
for(int i=1;i<=all;i++){
if(i>1)
update(1,all,1,1,i-1,b[i-1]-b[i]);
for(auto j:vec[i])
update(1,all,1,1,j.first,j.second);
ll v=query(1,all,1,1,i);
if(v>ans)
ans=v,x1=y1=b[p],x2=y2=b[i];
}
printf("%lld\n",ans);
printf("%d %d %d %d\n",x1,y1,x2,y2);
return 0;
}