题意:
一个 (n*n) 矩阵 (A) ,有 (m_1) 个操作:给 (x_1;x_2;y_1;y_2;w) ,对所有(A_{ij}) ((iin[x_1,x_2]) 且 (jin[y_1,y_2]) )加上 (w) ;
有 (m_2) 个询问:给 (x_1;x_2;y_1;y_2) ,求出(A_{ij}) ((iin[x_1,x_2]) 且 (jin[y_1,y_2]) )的最大值。
输入:
第 (1) 行 (3) 个整数 (n;m_1;m_2) ( (1≤n≤2000,1≤m_1≤5*10^4,1≤m_2≤5*10^5) );
之后 (m_1) 行,每行 (5) 个整数:(x_1;x_2;y_1;y_2;w) ( (1≤x_1≤x_2≤n,1≤y_1≤y_2≤n,1≤w≤10^9) );
之后 (m_2) 行,每行 (4) 个整数:(x_1;x_2;y_1;y_2) ( (1≤x_1≤x_2≤n,1≤y_1≤y_2≤n) );
输出:
输出m2行,每行一个整数
官方题解:
n小,所以可以用 (O(n^2))计算出矩阵。然后可以用二维线段树求最值。
个人积累:
【一开始用树状数组求矩阵,明明都是二维差分的思路,我却没想到用二维差分直接 (O(n^2)) 求矩阵....
【练习不足o(︶︿︶)o
【然后因为这个树状数组建了四个 (c[maxn][maxn]) (MLE) ,原本以为线段树 (tr[maxn<<2][maxn<<2]) 才可能 (MLE) 来着。。结果并不
因为是确定了矩阵A的具体的值,所以线段树无需修改,只需要静态求最值,所以简单多了;
至于二维的建法:以 (x) 轴为外部,对每个具体的 (x_i),对 (y) 轴去建它的子树 (sg[K].build(1,1,n)) ;
然后! 当 (sg[K]) 每得到一个 (sg[K].ma[k]) 时,(up) 回去,就是 (sg[K>>1].ma[k]=max(sg[K>>1].ma[k],sg[K].ma[k])) ;
这样就建好了!
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e3+5;
const int inf=0x3f3f3f3f;
ll a[maxn][maxn];
int n;
ll ma[maxn<<1][maxn<<1];
struct SG1{
void up(int K,int k)
{
ma[K>>1][k]=max(ma[K>>1][k],ma[K][k]);
if(K>>1)up(K>>1,k);
}
void build(int K,int k,int l,int r,int y)
{
if(l==r)
{
ma[K][k]=a[l][y];
up(K,k);
return;
}
int mid=(l+r)>>1;
build(K,k<<1,l,mid,y);build(K,k<<1|1,mid+1,r,y);
ma[K][k]=max(ma[K][k<<1],ma[K][k<<1|1]);
up(K,k);
}
ll query(int K,int k,int l,int r,int tl,int tr)
{
if(tl<=l&&r<=tr)return ma[K][k];
int mid=(l+r)>>1;
ll res=0;
if(tl<=mid)res=query(K,k<<1,l,mid,tl,tr);
if(tr>mid&&res<ma[K][k<<1|1])res=max(res,query(K,k<<1|1,mid+1,r,tl,tr));
return res;
}
}sg;
inline void build(int k,int l,int r)
{
if(l==r)
{
sg.build(k,1,1,n,l);
return;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);build(k<<1|1,mid+1,r);
}
inline ll query(int k,int l,int r,int x1,int y1,int x2,int y2)
{
if(y1<=l&&r<=y2)return sg.query(k,1,1,n,x1,x2);
int mid=(l+r)>>1;
ll res=0;
if(y1<=mid)res=query(k<<1,l,mid,x1,y1,x2,y2);
if(y2>mid&&res<ma[k<<1|1][1])res=max(res,query(k<<1|1,mid+1,r,x1,y1,x2,y2));
return res;
}
int main()
{
int m1,m2,x1,y1,x2,y2,w;
scanf("%d%d%d",&n,&m1,&m2);
while(m1--)
{
scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&w);
a[x1][y1]+=w;a[x2+1][y2+1]+=w;
a[x1][y2+1]-=w;a[x2+1][y1]-=w;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1];
build(1,1,n);
while(m2--)
{
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
printf("%lld
",query(1,1,n,x1,y1,x2,y2));
}
}