题意
给 (a_1,a_2,...,a_n),(b_1,b_2,...,b_m),((x_1,y_1,w_1),(x_2,y_2,w_2),...,(x_p,y_p,w_p)),
问
[max_{1le ile n,1le jle m}{sum_{x_k<a_i,y_k<b_j}w_k-a_i-b_j}
]
其实就是分别选一个 (a_i,b_j),求矩形 ((0,0),(a_i,b_j)) 内部的点的 (w) 总和减 (a_i+b_j) 的最大值
题解
这种偏序问题基本上都可以考虑用线段树解决
借助扫描线的思维,枚举 x 轴枚举,线段树维护 y 轴
沿着 x 轴依次将点值加入其 y 轴对应坐标,然后直接查询线段树中的最大值
这个线段树显然应该维护前缀和,这样我们的到的最大值就是前缀和的最大值
就是问题的答案了
当然最初时要将 (b_j) 从线段树上减去
代码
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef pair<int,LL> PII;
const int inf=0x3f3f3f3f;
const LL INF=0x3f3f3f3f3f3f3f3f;
const int MAXN=2e5+10;
const int MAXM=1e6+10;
int n,m,p;
PII a[MAXN],b[MAXN],temp[MAXN];
struct Turp{
int x,y,w;
}t[MAXN];
bool cmp(Turp a,Turp b){return a.x<b.x;}
struct SegTree{
#define mid ((l+r)>>1)
LL maxv[MAXM*4],tag[MAXM*4];
void pushdown(int id){
maxv[id<<1]+=tag[id];tag[id<<1]+=tag[id];
maxv[id<<1|1]+=tag[id];tag[id<<1|1]+=tag[id];
tag[id]=0;
}
void update(int id,int l,int r,int L,int R,LL x,int opt){
if(L<=l&&r<=R)
if(opt) {maxv[id]+=x;tag[id]+=x;return;}
else {maxv[id]=max(maxv[id],x);return;}
if(tag[id]) pushdown(id);
if(L<=mid) update(id<<1,l,mid,L,R,x,opt);
if(R>mid) update(id<<1|1,mid+1,r,L,R,x,opt);
maxv[id]=max(maxv[id<<1],maxv[id<<1|1]);
}
#undef mid
}tr;
int main(){
scanf("%d%d%d",&n,&m,&p);
for(int i=1;i<=n;i++) scanf("%d%d",&a[i].first,&a[i].second);
for(int i=1;i<=m;i++) scanf("%d%d",&b[i].first,&b[i].second);
for(int i=1;i<=p;i++) scanf("%d%d%d",&t[i].x,&t[i].y,&t[i].w);
sort(a+1,a+n+1);
sort(b+1,b+m+1);
sort(t+1,t+p+1,cmp);
memset(tr.maxv,0xc0,sizeof(tr.maxv));
LL temp=-INF;
for(int i=1e6,j=m;i>=0;i--){
while(i<b[j].first) temp=max(temp,-b[j].second),j--;
tr.update(1,0,1e6,i,i,temp,0);
}
LL ans=-INF;
for(int i=1,j=1;i<=n;i++){
while(j<=p&&t[j].x<a[i].first) tr.update(1,0,1e6,t[j].y,1e6,t[j].w,1),j++;
ans=max(ans,tr.maxv[1]-a[i].second);
}
cout<<ans<<endl;
return 0;
}