`

zoj3540

阅读更多

/*
其实就是把总共的 放置次数减去不能放置的那些就行了。而不能放置的 那部分是一个个矩形 !
所以问题 就转化为举行并的面积了。 
*/
#include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std;
const int N = 50005; //矩形的最大个数
typedef int typev;
typedef long long ll;
struct seg{
	int l, r;
	int c;    //覆盖数
	typev m;  //覆盖长度
}segs[N<<3];
struct li{
	typev x, ly, hy; //ly为小的,hy为大的
	void set(typev x, typev ly, typev hy){
		this->x = x, this->ly = ly, this->hy = hy;
	}
	bool is_l;   //标记是否是左边的线段
}lis[N*2];
//左下角是(x1,y1),右上角是(x2,y2), x1<x2,y1<y2的矩形
struct rect{
	typev x1, x2, y1, y2;
}rs[N];
typev y[N<<1];
int n, cnt;
typev xs[N][2], ys[N][2];
int w, h, m;

bool cmp(li l1, li l2){
	return l1.x < l2.x;
}
void build(int id, int l, int r){
	segs[id].l = l, segs[id].r = r, segs[id].m = segs[id].c = 0;
	if(l < r - 1){
		int mid = (l+r)>>1;
		build(2*id+1, l, mid);
		build(2*id+2, mid, r);
	}
}
int binary(int l, int r, typev k){
	int mid;
	while(l <= r){
		mid = (l+r)>>1;
		if(y[mid] >= k) r = mid-1;
		else l = mid+1;
	}
	return r+1;
}
void renew(int id){
	if(segs[id].c > 0) segs[id].m = y[segs[id].r] - y[segs[id].l];
	else if(segs[id].l == segs[id].r - 1) segs[id].m = 0;
	else{
		segs[id].m = segs[2*id+1].m + segs[2*id+2].m;
	}
}
// 可以把insert和del合为一个函数
void modify(int id, int l, int r, int k){
	if(segs[id].l >= l && segs[id].r <= r){
		segs[id].c += k;
		renew(id);
	}else if(segs[id].l < segs[id].r - 1){
		int mid = (segs[id].l + segs[id].r)>>1;
		if(l < mid) modify(2*id+1, l, r, k);
		if(r > mid) modify(2*id+2, l, r, k);
		renew(id);
	}
}
//n个矩形的面积并
ll unionArea(rect* rs, int n){
	if(n <= 0) return 0;
	int i;
	typev x1, y1, x2, y2, py1, py2;
	ll area;
	for(i = 0; i < n; i++){
		x1 = rs[i].x1; y1 = rs[i].y1;
		x2 = rs[i].x2; y2 = rs[i].y2;
		lis[2*i].set(x1, y1, y2);
		lis[2*i].is_l = true;
		lis[2*i+1].set(x2, y1, y2);
		y[2*i] = y1;
		y[2*i+1] = y2;
		lis[2*i+1].is_l = false;
	}
	n <<= 1;
	sort(y, y + n);
	sort(lis, lis+n, cmp);
	cnt = unique(y, y + n) - y;
	build(0, 0, cnt-1);
	area = 0;
	for(i = 0; i < n-1; i++){
		py1 = binary(0, cnt-1, lis[i].ly);
		py2 = binary(0, cnt-1, lis[i].hy);
		if(lis[i].is_l) modify(0, py1, py2, 1);
		else modify(0, py1, py2, -1);
		area += ((ll)lis[i+1].x - lis[i].x) * (segs[0].m);
	}
	return area;
}

//输入一个正整数
template<typename T>
void getNum(T& ans){
	ans = 0;
	char ch;
	while(true){
		ch = getchar();
		if(ch >= '0' && ch <= '9') break;
	}
	ans = ch -'0';
	while(true){
		ch = getchar();
		if(!(ch >= '0' && ch <= '9')) break;
		ans = ans*10+ch-'0';
	}
}
bool input(){
	if(scanf("%d%d%d%d", &w, &h, &n, &m) == EOF) return false;
	int i;
	for(i = 0; i < n; i++){
		getNum(xs[i][0]);
		getNum(ys[i][0]);
		getNum(xs[i][1]);
		getNum(ys[i][1]);
	}
	return true;
}
ll cal(){
	if(w-m+1<=0) return 0;
	ll ans=(ll)h*(w-m+1);
	int i, rn;
	for(i=rn=0; i<n; i++){
		if(xs[i][0]-m >= 0){
			rs[rn].x1 = xs[i][0]-m;
		}else{
			rs[rn].x1 = 0;
		}
		if(xs[i][1] <= (w-m+1)){
			rs[rn].x2=xs[i][1];
		}else{
			rs[rn].x2=w-m+1;
		}
//		if(rs[rn].x1>=rs[rn].x2) continue;
		if(rs[rn].x1>rs[rn].x2) continue;
		rs[rn].y1=ys[i][0]-1;
		rs[rn].y2=ys[i][1];
		if(rs[rn].y1>rs[rn].y2) continue;
		rn++;
	}
	ans -= unionArea(rs, rn);
	return ans;
}
void solve(){
	ll ans=cal();
	int i;
	if(m > 1){ //这里是要给trick,m为1的时候,横向的和竖向的都是一样的 !
		swap(w, h);
		for(i=0; i<n; i++){
			swap(xs[i][0], ys[i][0]);
			swap(xs[i][1], ys[i][1]);
		}
		ans += cal();
	}
	cout<<ans<<endl;

//	printf("%I64d\n", ans);
//	printf("%lld\n", ans);
}
int main(){
	//freopen("in.txt", "r", stdin);

	while(input()) solve();
	return 0;
}
 
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics