题目链接
没往前缀和想,写了个二维线段树(要开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;
}
本文介绍了一种使用二维前缀和算法解决矩形区域查询问题的方法,对比了二维线段树的实现,详细展示了如何通过二维前缀和进行矩形区域的更新和查询,提供了一个AC代码示例。
&spm=1001.2101.3001.5002&articleId=100018255&d=1&t=3&u=77349db7ec4a47ee8c7ba9a896e49c7a)
991





