链接:https://ac.nowcoder.com/acm/problem/201927
来源:牛客网
题目描述
It's time to have a break and implement something.
You are given an n×nn\times nn×n matrix A{A}A. All the elements are zero initially.
First, you need to perform m1m_1m1 range addition operations. For each operations, you are given x1,y1,x2,y2,w (1≤x1≤x2≤n,1≤y1≤y2≤n)x_1, y_1, x_2, y_2, w~(1\leq x_1\leq x_2 \leq n, 1\leq y_1 \leq y_2\leq n)x1,y1,x2,y2,w (1≤x1≤x2≤n,1≤y1≤y2≤n).You need to add w to all the elements Ai,jA_{i,j}Ai,j where x1≤i≤x2x_1\leq i\leq x_2x1≤i≤x2 and y1≤j≤y2y_1\leq j \leq y_2y1≤j≤y2.
Then you need to perform m2m_2m2 range maximum queries. For each operations, you are given x1,y1,x2,y2 (1≤x1≤x2≤n,1≤y1≤y2≤n)x_1, y_1, x_2, y_2~(1\leq x_1\leq x_2 \leq n, 1\leq y_1 \leq y_2\leq n)x1,y1,x2,y2 (1≤x1≤x2≤n,1≤y1≤y2≤n). You need to answer the maximum element among the elements Ai,jA_{i,j}Ai,j that satisify x1≤i≤x2x_1\leq i\leq x_2x1≤i≤x2 and y1≤j≤y2y_1\leq j \leq y_2y1≤j≤y2.
输入描述:
The first line contains three integers n,m1,m2 (1≤n≤2000,1≤m1≤5×104,1≤m2≤5×105)n, m_1, m_2~(1\leq n\leq 2000, 1\leq m_1 \leq 5 \times 10^4, 1\leq m_2 \leq 5 \times 10^5)n,m1,m2 (1≤n≤2000,1≤m1≤5×104,1≤m2≤5×105) Each of the following m1m_1m1 lines contains five integers x1,y1,x2,y2,w (1≤x1≤x2≤n,1≤y1≤y2≤n,1≤w≤109)x_1, y_1, x_2, y_2, w~(1\leq x_1\leq x_2\leq n, 1\leq y_1 \leq y_2 \leq n, 1\leq w \leq 10^9)x1,y1,x2,y2,w (1≤x1≤x2≤n,1≤y1≤y2≤n,1≤w≤109).Each of the following m2m_2m2 lines contains four integers x1,y1,x2,y2 (1≤x1≤x2≤n,1≤y1≤y2≤n)x_1, y_1, x_2, y_2~(1\leq x_1\leq x_2\leq n, 1\leq y_1 \leq y_2 \leq n)x1,y1,x2,y2 (1≤x1≤x2≤n,1≤y1≤y2≤n).
输出描述:
Output m2m_2m2 lines, each of which contains one integer.
示例1
输入
复制5 5 5 1 1 4 5 4 4 1 4 1 10 1 3 3 3 3 1 1 5 5 8 2 4 4 5 8 2 1 2 1 4 1 5 4 1 2 3 5 2 1 5 3 1 3 5 5
5 5 5 1 1 4 5 4 4 1 4 1 10 1 3 3 3 3 1 1 5 5 8 2 4 4 5 8 2 1 2 1 4 1 5 4 1 2 3 5 2 1 5 3 1 3 5 5
输出
复制12 22 20 22 20
12 22 20 22 20
思路:
首先,因为 前缀和 和 差分 互为逆运算,即:原序列 差分后再求前缀和即可得到原序列。
因为这里是对多个矩阵区域内的所有元素进行add操作且初始矩阵每个元素为0,所以用差分就可以省去对每个元素挨个操作,用差分序列上的操作来代替,然后再求多次操作后的差分序列的前缀和即可得到原二维矩阵序列。
因为差分序列的递推公式是这样的:
所以对于矩阵区域内的所有元素进行一个add操作,二维差分序列对应的就是四个位置的修改:
因为(x1,y1) ~ (x2,y2) 每个数都加了w,其他数可相对视为0,那么:
cf[x1][y1]=a[x1][y1]-a[x1][y1-1]-a[x1-1][y1]+a[x1-1][y1-1]=w-0-0+0=w, 所以对应a[x1][y1]+=w
cf[x1][y2+1]=a[x1][y2+1]-a[x1][y2+1-1]-a[x2-1][y2+1]+a[x2-1][y2+1-1]=0-w-0+0=w 对应a[x1][y2+1]-=w
另外两项以此类推。。。
二维差分前缀和参考链接:https://www.cnblogs.com/jiamian/p/11523152.html
https://www.cnblogs.com/i-cookie/p/11517651.html
处理好后,剩下的就是对这个二维矩阵求二维区域内的最值,这个可用二维线段树实现:
参考博客:https://www.cnblogs.com/mollnn/p/12342681.html
大体长这个样:
横向和纵向交替二分
具体参考代码。
代码:
#include <iostream>
#include <algorithm>
#include <cstring>
#define int long long
using namespace std;
const int maxn=2e3+5;
int a[maxn][maxn],tr[maxn*maxn*4],res;
int n,m1,m2;
int qxl,qyl,qxr,qyr;
void push_up(int p){tr[p]=max(tr[p<<1],tr[p<<1|1]);}
void build(int p,int xl,int xr,int yl,int yr,int son)
{
if(xl>xr||yl>yr) return;
if(xl==xr && yl==yr){
tr[p]=a[xl][yl];
return;
}
if(son){
build(p<<1,xl,xl+xr>>1,yl,yr,!son);
build(p<<1|1,(xl+xr>>1)+1,xr,yl,yr,!son);
push_up(p);
}
else{
build(p<<1,xl,xr,yl,yl+yr>>1,!son);
build(p<<1|1,xl,xr,(yl+yr>>1)+1,yr,!son);
push_up(p);
}
}
void query(int p,int xl,int xr,int yl,int yr,int son)
{
if(tr[p]<res) return;
if(xl>qxr||xr<qxl||yl>qyr||yr<qyl) return;
if(xl>=qxl&&xr<=qxr&&yl>=qyl&&yr<=qyr){
res=max(res,tr[p]);
return;
}
if(son){
query(p<<1,xl,xl+xr>>1,yl,yr,!son);
query(p<<1|1,(xl+xr>>1)+1,xr,yl,yr,!son);
}
else{
query(p<<1,xl,xr,yl,yl+yr>>1,!son);
query(p<<1|1,xl,xr,(yl+yr>>1)+1,yr,!son);
}
}
signed main()
{
cin>>n>>m1>>m2;
while(m1--){
int x1,y1,x2,y2,w;
cin>>x1>>y1>>x2>>y2>>w;
a[x1][y1]+=w;
a[x1][y2+1]-=w;
a[x2+1][y1]-=w;
a[x2+1][y2+1]+=w;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
a[i][j]=a[i][j]+a[i-1][j]+a[i][j-1]-a[i-1][j-1];
}
}
build(1,1,n,1,n,1);
while(m2--){
cin>>qxl>>qyl>>qxr>>qyr;
res=0;
query(1,1,n,1,n,1);
cout<<res<<endl;
}
return 0;
}