线段树求矩形并模板

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define  lson(i) (idx << 1)
#define  rson(i) ((idx << 1) ^ 1)
using namespace std;

const int N = 1010;
double y[N];
struct segment{
	double x, y1, y2;
	int flag;
	segment(){}
	segment(const double x, const double y1, const double y2, const int flag){
		this->x = x, this->y1 = y1, this->y2 = y2, this->flag = flag; 	
	}
	bool operator < (const segment &a) const {
		return x < a.x;
	}
}line[N];
struct segTree{
	int lc, rc, cover;
	double up, down, len;
}arr[N * 4];

void pushUp(int idx){
	if(arr[idx].cover > 0)	
		arr[idx].len = arr[idx].up - arr[idx].down;
 	else 
		arr[idx].len = arr[lson(idx)].len + arr[rson(idx)].len;
}

void build(int idx, int l, int r){
	arr[idx].lc = l, arr[idx].rc = r;
	arr[idx].up = y[r], arr[idx].down = y[l];
	arr[idx].len = arr[idx].cover = 0;
	if(r - l == 1)
		return ;
	int mid = (l + r) >> 1;
	/**
	这里和普通的线段树有点不同,不能以左区间[1,mid],右区间[mid+1,r]来建树
	如果这样建会漏掉一些线段,比如10,20,30,40这些点来建树,按普通的建法是
	[10,20], [30,40],这样[20,30]这跟线段就漏掉了 
	所以需要左区间[l,mid],右区间[mid,r]这样来建;建出来是[10,20],[20,30],[30,40]
	这样就没线段漏掉了.
	**/
	build(lson(idx), l, mid);
	build(rson(idx), mid, r);
}

void update(int idx, int l, int r, int val){
	if(arr[idx].lc > r || l > arr[idx].rc)
		return ;
	if(arr[idx].lc >= l && arr[idx].rc <= r){
		arr[idx].cover += val;
		pushUp(idx);
		return ;		
	}
	update(lson(idx), l, r, val);
	update(rson(idx), l, r, val);
	pushUp(idx);
}

int main(){
	int n, no = 1;
	while(cin >> n, n){
		int i, idx = 1;
		double x1, x2, y1, y2;
		for(i = 1;i <= n;i++){
			cin >> x1 >> y1 >> x2 >> y2;
			line[idx] = segment(x1, y1, y2, 1);
			y[idx++] = y1;
			
			line[idx] = segment(x2, y1, y2, -1);
			y[idx++] = y2;
		}
		sort(y + 1, y + idx);
		sort(line + 1, line + idx);
		/**以y轴建树**/ 
		build(1, 1, idx - 1);
		double res = 0;
		for(i = 1;i < idx;i++){
			res += arr[1].len * (line[i].x - line[i - 1].x);
			/**二分出当前扫描线y1,y2的位置**/
			int fir = lower_bound(y + 1, y + idx, line[i].y1) - y;
			int sec = lower_bound(y + 1, y + idx, line[i].y2) - y;
			update(1, fir, sec, line[i].flag);
		}
		printf("Test case #%d\nTotal explored area: %.2f\n\n", no++, res);							
	}
	return 0;	
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值