2017acm香港区域赛 Black and White

题目:

有一个初始颜色全为白色的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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值