二维前缀和(HDU - 6514 Monitor)

本文介绍了一种使用二维前缀和算法解决矩形区域查询问题的方法,对比了二维线段树的实现,详细展示了如何通过二维前缀和进行矩形区域的更新和查询,提供了一个AC代码示例。

题目链接
没往前缀和想,写了个二维线段树(要开16倍)爆内存(连编译都过不去的那种),不知道我的那个二维线段树有没有卵用。
下面是ac代码:

#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <cstdio>
#include <cstdlib>
#define ll long long
using namespace std;
const int  N = 1e6+5;
struct Node
{
    int id;
    int x1, x2, y1, y2;
}qu[N];
int main()
{
    int n, m;
    while(scanf("%d%d", &n, &m) != EOF)
    {
        int mp[n+2][m+2];
        memset(mp, 0, sizeof(mp));
        int q;
        scanf("%d", &q);
        while(q--)
        {
            int x1, x2, y1, y2;
            scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
            mp[x1][y1]++;
            mp[x1][y2+1]--;
            mp[x2+1][y1]--;
            mp[x2+1][y2+1]++;
        }
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++)
                mp[i][j] += mp[i-1][j] + mp[i][j-1] - mp[i-1][j-1];
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++)
                mp[i][j] = mp[i][j]>0?1:0, mp[i][j] += mp[i-1][j] + mp[i][j-1] - mp[i-1][j-1];
        scanf("%d", &q);
        while(q--)
        {
            int x1, y1;
            int x2, y2;
            scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
            if(mp[x2][y2] - mp[x1-1][y2] - mp[x2][y1-1] + mp[x1-1][y1-1] == (y2 - y1 + 1) * (x2 - x1 + 1))
                puts("YES");
            else puts("NO");

        }
    }
}

下面是瞎写的代码:
注意这不是ac代码!

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 1e7 + 5;
struct Node
{
    int x1, x2;
    int y1, y2;
    bool val;
    bool flag;
    int add;
}tr[N*6];
int mx = 0;
void build(int p, int x1, int y1, int x2, int y2)
{
    mx = max(mx, p);
    if (x1 > x2 || y1 > y2) return;
    tr[p].x1 = x1; tr[p].x2 = x2;
    tr[p].y1 = y1; tr[p].y2 = y2;
    tr[p].flag = 1;
    tr[p].add = 0; tr[p].val = 0;
    if (x1 == x2 && y1 == y2)
        return;
    int midx = (x1 + x2) >> 1;
    int midy = (y1 + y2) >> 1;
    build(p * 4 - 2, x1, y1, midx, midy);
    build(p * 4 - 1, x1, midy + 1, midx, y2);
    build(p * 4, midx + 1, y1, x2, midy);
    build(p * 4 + 1, midx + 1, midy + 1, x2, y2);
}
inline bool che(int p, int x1, int x2, int y1, int y2)
{
    return x1 <= tr[p].x1 && x2 >= tr[p].x2 && y1 <= tr[p].y1 && y2 >= tr[p].y2;
}
void spread(int p)
{
    if (tr[p].add)
    {
        tr[p * 4 - 2].val = tr[p * 4].add = 1;
        tr[p * 4 - 1].val = tr[p * 4 + 1].add = 1;
        tr[p * 4].val = tr[p * 4 + 2].add = 1;
        tr[p * 4 + 1].val = tr[p * 4 + 3].add = 1;
        tr[p].add = 0;
    }
}
void change(int p, int x1, int x2, int y1, int y2)
{
    if (!tr[p].flag) return;
    if (che(p, x1, x2, y1, y2))
    {
    //    cout << "ss" << endl;
        tr[p].add = 1;
        tr[p].val = 1;
        return;
    }
    spread(p);
    int midx = (tr[p].x1 + tr[p].x2) >> 1;
    int midy = (tr[p].y1 + tr[p].y2) >> 1;
    if (x1 <= midx && y1 <= midy) change(p * 4 - 2, x1, x2, y1, y2);
    if (x1 <= midx && y2 > midy) change(p * 4 - 1, x1, x2, y1, y2);
    if (x2 > midx && y1 <= midy) change(p * 4, x1, x2, y1, y2);
    if (x2 > midx && y2 > midy) change(p * 4 + 1, x1, x2, y1, y2);
    tr[p].val = tr[p * 4 - 2].val&&tr[p * 4 - 1].val&&tr[p * 4].val&&tr[p * 4 + 1].val;
}
int ask(int p, int x1, int x2, int y1, int y2)
{
    if (!tr[p].flag) return 1;
    if (che(p, x1, x2, y1, y2))
        return tr[p].val;
    spread(p);
    int midx = (tr[p].x1 + tr[p].x2) >> 1;
    int midy = (tr[p].y1 + tr[p].y2) >> 1;
    int gg = 1;
    if (x1 <= midx && y1 <= midy) gg = gg && ask(p * 4 - 2, x1, x2, y1, y2);
    if (x1 <= midx && y2 > midy) gg = gg && ask(p * 4 - 1, x1, x2, y1, y2);
    if (x2 > midx && y1 <= midy) gg = gg && ask(p * 4, x1, x2, y1, y2);
    if (x2 > midx && y2 > midy) gg = gg && ask(p * 4 + 1, x1, x2, y1, y2);
    return gg;
}
void print()
{
    for (int i = 1; i <= mx; i++)
    {
        cout << tr[i].x1 << " " << tr[i].y1 << endl;
        cout << tr[i].x2<< " " << tr[i].y2 << endl;
        cout << tr[i].val << endl;
        cout << "------" << endl;
    }
}
int main()
{
    int n, m;
    while (scanf("%d%d", &n, &m) != EOF)
    {
        int q;
        scanf("%d", &q);
        build(1, 1, 1, n, m);
        while (q--)
        {
            int x1, x2, y1, y2;
            scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
            change(1, x1, x2, y1, y2);
        }
        //print();
        scanf("%d", &q);
        while (q--)
        {
            int x1, x2, y1, y2;
            scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
            if (ask(1, x1, x2, y1, y2))
                puts("YES");
            else puts("NO");
        }
    }
    return 0;
}
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值