Practice for KD Tree(差分+前缀和+线段树(二维))

该博客介绍了如何使用差分和线段树解决矩阵范围内元素的加法操作以及后续的范围最大值查询问题。首先解释了差分与前缀和的逆运算关系,然后说明了在初始全零矩阵上使用差分处理范围添加操作的原理,接着阐述了二维线段树如何用于求解二维区域内的最大值。提供了相关参考链接和示例输入输出。
摘要由CSDN通过智能技术生成

链接: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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值