题目:
有一个初始颜色全为白色的n*n的棋盘,每次选一个长方形区域反转颜色,问最后会有几个黑色格子。n,k<=10000
分析:
和扫描线求面积并一样。记录每条横边,向x轴投影。只不过不区分上边和下边。按高度排序后,对于每条边,向x轴投影,将投影的区间进行一次 xor 1 的操作。所以线段树维护区间异或操作,然后每次询问区间和。
代码:
#include<bits/stdc++.h>
#define lson rt<<1,l,(l+r)/2
#define rson rt<<1|1,(l+r)/2+1,r
using namespace std;
const int MAXN = 1e4+5;
int n,k,cnt;
struct Edge {
int l,r,h;
bool operator < (const Edge &e) const {
return h < e.h;
}
}e[MAXN<<1];
struct Seg_Tree{
int sum[MAXN << 2], tag[MAXN<<2];
void build() {
memset(sum,0,sizeof sum);
memset(tag,0,sizeof tag);
}
void pushup(int rt) {
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
void pushdown(int rt,int l,int r) {
if(tag[rt]){
tag[rt<<1] ^= tag[rt];
tag[rt<<1|1] ^= tag[rt];
sum[rt<<1] = (l+r)/2 - l + 1 - sum[rt<<1];
sum[rt<<1|1] = r - (l+r)/2 - sum[rt<<1|1];
tag[rt] = 0;
}
}
void update(int L,int R,int rt,int l,int r) {
if(L<=l && R>=r){
tag[rt] ^= 1;
sum[rt] = (r-l+1) - sum[rt];
return;
}
pushdown(rt,l,r);
if(L<=(l+r)/2) update(L,R,lson);
if(R>(l+r)/2) update(L,R,rson);
pushup(rt);
}
}t;
int main() {
ios::sync_with_stdio(false);
int T;
cin >> T;
while(T--) {
cin >> n >> k;
cnt = 0;
for(int i=0;i<k;i++){
int xlow,xhigh,ylow,yhigh;
cin >> xlow >> xhigh >> ylow >> yhigh;
e[++cnt] = {xlow,xhigh,ylow};
e[++cnt] = {xlow,xhigh,yhigh+1};
}
sort(e+1,e+cnt+1);
int ans = 0;
t.build();
for(int i=1;i<cnt;i++) {
t.update(e[i].l,e[i].r,1,1,1e4+2);
ans += t.sum[1]*(e[i+1].h-e[i].h);
}
cout << ans << endl;
}
return 0;
}