题意:
给一个n*n的矩阵,初始全是白色,进行m次操作,每次操作是让一个子矩阵的颜色翻转,求最后有几个黑色的方格。
题解:
每行分别处理,将一个子矩阵拆成两条线段,分别是上底和下底,然后按照线段的高度排序。
每到一行,将所有高度等于该行的下底的线段加入线段树中,表示对这个线段进行翻转,更新答案,最后将所有高度等于该行的上底的线段加入线段树中,表示对这个线段进行翻转。
代码:
#include<bits/stdc++.h>
#include<hash_map>
#define N 10010
#define INF 0x3f3f3f3f
#define eps 1e-10
#define pi 3.141592653589793
#define LL long long
#define pb push_back
#define cl clear
#define si size
#define lb lowwer_bound
#define mem(x) memset(x,0,sizeof x)
#define sc(x) scanf("%d",&x)
#define scc(x,y) scanf("%d%d",&x,&y)
#define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;
struct Seg
{
int h,l,r,flag;
bool operator < (const Seg &z) const
{
if (h==z.h) return flag>z.flag;
return h<z.h;
}
}seg[N<<1];
int mk[N<<2],sum[N<<2];
inline void nodeupdata(int x,int l,int r)
{
mk[x]^=1;
sum[x]=(r-l+1)-sum[x];
}
inline void pushdown(int x,int l,int r)
{
if (!mk[x]) return;
int t=(l+r)>>1;
nodeupdata(x<<1,l,t);
nodeupdata(x<<1|1,t+1,r);
mk[x]=0;
}
void updata(int x,int l,int r,int fl,int fr)
{
if (l==fl && r==fr)
{
nodeupdata(x,l,r);
return;
}
pushdown(x,l,r);
int t=(l+r)>>1;
if (fr<=t) updata(x<<1,l,t,fl,fr);else
if (fl>t) updata(x<<1|1,t+1,r,fl,fr);else
{
updata(x<<1,l,t,fl,t);
updata(x<<1|1,t+1,r,t+1,fr);
}
sum[x]=sum[x<<1]+sum[x<<1|1];
}
int main()
{
int T;
sc(T);
while(T--)
{
mem(mk);
mem(sum);
int n,m;
scc(n,m);
for (int i=1;i<=m;i++)
{
int x1,x2,y1,y2;
scc(x1,x2);scc(y1,y2);
seg[i*2-1]=Seg{y1,x1,x2,1};
seg[i*2]=Seg{y2,x1,x2,-1};
}
sort(seg+1,seg+m*2+1);
int ans=0; int j=1; m<<=1;
for (int i=1;i<=n;i++)
{
while(j<=m && seg[j].h<=i && seg[j].flag==1)
{
updata(1,1,n,seg[j].l,seg[j].r);
j++;
}
ans+=sum[1];
while(j<=m && seg[j].h<=i)
{
updata(1,1,n,seg[j].l,seg[j].r);
j++;
}
}
printf("%d\n", ans );
}
return 0;
}