答案的计算有两种方法:
1.直接计算红雾点个数:标记为 1 的行的个数和标记为 0 的列的个数的乘积 + 标记为 0 的行的个数和标记为 1 的列的个数的乘积
2.间接计算红雾点个数:被询问矩阵内点的总个数 - 标记为 1 的行和列的个数的乘积 - 标记为 0 的行和列的个数的乘积
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int N=1e5+5;
struct seg_tree
{
LL str[N<<2];
void pushup(int root)
{
str[root]=str[root*2]+str[root*2+1];
return;
}
void build(int root,int l,int r)
{
if(l==r)
{
str[root]=0;
return;
}
int mid=(l+r)>>1;
build(root*2,l,mid);
build(root*2+1,mid+1,r);
pushup(root);
return;
}
void update(int root,int l,int r,int u,int w)
{
if(l==r)
{
str[root]^=w;
return;
}
int mid=(l+r)>>1;
if(mid>=u) update(root*2,l,mid,u,w);
if(mid<u) update(root*2+1,mid+1,r,u,w);
pushup(root);
return;
}
LL query(int root,int l,int r,int ll,int rr)
{
if(ll<=l&&r<=rr) return str[root];
LL res=0;
int mid=(l+r)>>1;
if(mid>=ll) res+=query(root*2,l,mid,ll,rr);
if(mid<rr) res+=query(root*2+1,mid+1,r,ll,rr);
return res;
}
}strh,strl;
int n,m,q;
int main()
{
scanf("%d%d%d",&n,&m,&q);
strh.build(1,1,n);
strl.build(1,1,m);
while(q--)
{
int opt;
scanf("%d",&opt);
if(opt==1)
{
int x,y;
scanf("%d%d",&x,&y);
strh.update(1,1,n,x,1);
strl.update(1,1,m,y,1);
}
if(opt==2)
{
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
int hs=x2-x1+1,ls=y2-y1+1;
int sh=strh.query(1,1,n,x1,x2);
int sl=strl.query(1,1,m,y1,y2);
LL ans=1ll*sh*(ls-sl)+1ll*(hs-sh)*sl;//直接求有红雾的点的个数
// LL ans=1ll*hs*ls-1ll*sh*sl-1ll*(hs-sh)*(ls-sl);//通过总个数-没有红雾的点的个数
printf("%lld\n",ans);
}
}
return 0;
}
原文:https://www.cnblogs.com/Hawking-llfz/p/11586562.html