Codeforces 869E. The Untended Antiquity
题意:
在一张mxn的格子纸上,进行q次操作:
1,指定一个矩形将它用栅栏围起来。
2,撤掉一个已有的栅栏。
3,询问指定两点之间是否连通(即能否从其中一点不翻越栅栏走到另一点)
思路:
对于操作1,将给定的矩形哈希成一个数(可对点坐标进行进制哈希),对整个矩形所覆盖的点都累加上这个数;
对于操作2,则逆着把操作1的影响抵消掉;
对于操作3,看一下两点的值是否相同(相同表示他们被相同的矩形们所覆盖)。
至于每次矩形内的所有点的修改操作以及单点查值,使用二维树状数组来维护,用到了差分思想,维护的是差分数组,则单点查询即求差分数组的前缀和。具体可见代码,在图上画一画,不难理解
代码:
#include<bits/stdc++.h>
#define de(x) cout<<#x<<" = "<<x<<"
"
#define dd(x) cout<<#x<<" = "<<x<<" "
#define sz(x) int(x.size())
#define All(x) x.begin(),x.end()
#define fi first
#define se second
#define pb push_back
#define mp make_pair
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int,int> P;
typedef priority_queue<int> BQ;
typedef priority_queue<int,vector<int>,greater<int> > SQ;
const int maxn=3e3+10,INF=0x3f3f3f3f;
ll fw[maxn][maxn];
void add(int x,int y,ll c)
{
for (int i=x;i<maxn;i+=i&-i)
for (int j=y;j<maxn;j+=j&-j)
fw[i][j]+=c;
}
ll qry(int x,int y)
{
ll res=0;
for (int i=x;i;i-=i&-i)
for (int j=y;j;j-=j&-j)
res+=fw[i][j];
return res;
}
ll seed=2333;
inline ll Hash(int a,int b,int c,int d)
{
return a*seed*seed*seed+b*seed*seed+c*seed+d;
}
int main()
{
int n,m,q;
cin>>n>>m>>q;
for (int i=0;i<q;++i)
{
int op,x1,y1,x2,y2;
scanf("%d%d%d%d%d",&op,&x1,&y1,&x2,&y2);
if (op==3)
{
if (qry(x1,y1)==qry(x2,y2))
printf("Yes
");
else
printf("No
");
}
else
{
ll hs=Hash(x1,y1,x2,y2);
if (op==2)
hs=-hs;
add(x1,y1,hs);
add(x2+1,y2+1,hs);
add(x1,y2+1,-hs);
add(x2+1,y1,-hs);
}
}
return 0;
}