题意
n
⋅
n
n\cdot n
n⋅n的矩阵,初始为0,先执行
m
m
m次矩形加法,再询问
q
q
q次矩形最大值。
注意所有询问都在加法后面。
n
,
m
≤
5
e
4
,
q
≤
5
e
5
n,m\le5e4,q\le5e5
n,m≤5e4,q≤5e5.
题解
lxltql
二维平面的问题首先考虑扫描线,但由于矩形最值不具有查分的性质,所以我们需要手动在询问矩形中间砍一刀(类似于线段树中点的砍法),使其变成两个前缀(后缀)形式的矩形.。
然后就等价于从某个位置开始,支持区间加减,询问扫到某个位置时的历史最大值。
这是一个
t
r
i
v
a
l
trival
trival的线段树板子。注意按照上诉矩形的砍法,最多分了
O
(
l
o
g
)
O(log)
O(log)层,而每层中段与段之间需要撤销之前段的历史最值信息,最简单的写法是线段树加上一个极大值,使得当前最值成为历史最大值。
复杂度
O
(
(
n
+
m
)
log
2
n
+
q
log
n
)
O((n+m)\log^2 n+q\log n)
O((n+m)log2n+qlogn).
#include<bits/stdc++.h>
#define maxn 500050
using namespace std;
typedef long long LL;
const LL N=65536,M=1e10,inf=1e18;
struct node {
LL mx,hmx;
LL tag,htag;
} T[N<<1];
#define mx(k) T[k].mx
#define tag(k) T[k].tag
#define hmx(k) T[k].hmx
#define htag(k) T[k].htag
void build(int k,int l,int r) {
mx(k)=hmx(k)=0;
tag(k)=htag(k)=0;
if (l==r) return ;
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
}
void renew(int k,LL h,LL d) {
h=max(h,0LL);
htag(k)=max(htag(k),tag(k)+h);
tag(k)+=d;
hmx(k)=max(hmx(k),mx(k)+h);
mx(k)+=d;
}
void godown(int k) {
renew(k<<1,htag(k),tag(k));
renew(k<<1|1,htag(k),tag(k));
htag(k)=tag(k)=0;
}
void update(int k) {
mx(k)=max(mx(k<<1),mx(k<<1|1));
hmx(k)=max(hmx(k<<1),hmx(k<<1|1));
}
void change(int k,int l,int r,int a,int b,LL d) {
if (a<=l&&r<=b)
renew(k,d,d);
else {
godown(k);
int mid=(l+r)>>1;
if (a<=mid)
change(k<<1,l,mid,a,b,d);
if (b>mid)
change(k<<1|1,mid+1,r,a,b,d);
update(k);
}
}
LL query(int k,int l,int r,int a,int b) {
if (a>r||l>b) return -inf;
if (a<=l&&r<=b) return hmx(k);
godown(k);
int mid=(l+r)>>1;
return max(query(k<<1,l,mid,a,b),query(k<<1|1,mid+1,r,a,b));
}
struct seg {
int l,r,x;
bool operator < (const seg& s) const {
return x<s.x;
}
};
vector<seg> L[maxn],R[maxn];
int n,m,q;
int Log2(int x) { return !x?-1:Log2(x>>1)+1; }
LL ans[maxn];
vector<pair<seg,int> > LQ[maxn],RQ[maxn];
void Max(LL &a,LL b) {
a=max(a,b);
}
int main() {
scanf("%d%d%d",&n,&m,&q);
while (m--) {
int l1,l2,r1,r2,x;
scanf("%d%d%d%d%d",&l1,&l2,&r1,&r2,&x);
L[l1].push_back(seg{l2,r2,x});
R[r1].push_back(seg{l2,r2,x});
}
for (int i=0;i<q;++i) {
int l1,l2,r1,r2;
scanf("%d%d%d%d",&l1,&l2,&r1,&r2);
int t=max(Log2(l1^r1),0);
LQ[t].emplace_back(seg{l2,r2,r1},i);
RQ[t].emplace_back(seg{l2,r2,l1},i);
}
for (int t=0;(1<<t)<=N;++t) {
build(1,0,N-1);
LL cnt=0,sum=0,ALL=(1<<t)-1;
sort(LQ[t].begin(),LQ[t].end());
for (int i=0,j=0;i<N;++i) {
for (seg s:L[i])
change(1,0,N-1,s.l,s.r,s.x),++cnt;
for (;j<LQ[t].size()&&LQ[t][j].first.x==i;++j)
Max(ans[LQ[t][j].second],query(1,0,N-1,LQ[t][j].first.l,LQ[t][j].first.r)-sum*M);
for (seg s:R[i])
change(1,0,N-1,s.l,s.r,-s.x),++cnt;
if (ALL&~i) continue;
change(1,0,N-1,0,N-1,cnt*M);
sum+=cnt,cnt=0;
}
build(1,0,N-1),sum=cnt=0;
sort(RQ[t].rbegin(),RQ[t].rend());
for (int i=N-1,j=0;i>=0;--i) {
for (seg s:R[i])
change(1,0,N-1,s.l,s.r,s.x),++cnt;
for (;j<RQ[t].size()&&RQ[t][j].first.x==i;++j)
Max(ans[RQ[t][j].second],query(1,0,N-1,RQ[t][j].first.l,RQ[t][j].first.r)-sum*M);
for (seg s:L[i])
change(1,0,N-1,s.l,s.r,-s.x),++cnt;
if (ALL&i) continue;
change(1,0,N-1,0,N-1,cnt*M);
sum+=cnt,cnt=0;
}
}
for (int i=0;i<q;++i)
printf("%lld\n",ans[i]);
return 0;
}