题目:
有一个初始颜色全为白色的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; }