扫描线+线段树

10 篇文章 0 订阅
1 篇文章 0 订阅

污染面积

问题描述

小明的家旁边有条河流,但最近,周围的三个工厂开始向这条河排放污水,这条河的一部分被污染了,被一个工厂污染的部分可以看做一个矩形,现在小明想知道这条河被污染的面积是多少。

 

输入

第一行一个整数t,表示有多少组数据,之后每一组数据包括三行,每一行有lx, ly, rx, ry四个整数,表示被一个工厂污染的矩形的左下角与右上角,保证每个数都在[-100000,100000]之间,lx<rx,ly<ry。

 

输出

对于每组数据输出一行,每行一个整数表示被污染的面积。

 

样例输入

1

1 1 4 4

3 2 6 3

5 1 8 4

 

样例输出

19

 

思路。这题很简单,就是简单的容斥原理即可

#include <iostream>
#include <algorithm>
#include <cassert>
using namespace std;
#include <stdio.h>

struct point { 
	int x, y; 
	point(int x,int y) :x(x),y(y)	{}
	point(){}
};
typedef long long ll;
struct rect {
	point l, r;
	rect() {}
	rect(point a, point b) : l(a), r(b) {}
	ll area() {	return (r.x - l.x) * 1LL * (r.y - l.y);		}
	rect getit(rect s) {
		int left, right, up, down;
		if (l.x >= s.r.x||l.y >= s.r.y||r.x <= s.l.x||r.y <= s.l.y)
			return rect(point(0,0),point(0,0));
		left = max(l.x, s.l.x);
		right = min(r.x, s.r.x);
		down = max(l.y, s.l.y);
		up = min(r.y, s.r.y);
		return rect(point(left,down),point(right,up));
	}
};
int main(void)
{
	int t;
	scanf("%d", &t);
	while (t--) {
		rect s1, s2, s3;
		int a, b, c, d;
		scanf("%d%d%d%d", &a, &b, &c, &d);
		assert(a < c&&b < d);
		s1 = rect(point(a,b), point(c,d));
		scanf("%d%d%d%d", &a, &b, &c, &d);
		assert(a < c&&b < d);
		s2 = rect(point(a,b),point(c,d));
		scanf("%d%d%d%d", &a, &b, &c, &d);
		assert(a < c&&b < d);
		s3 = rect(point(a,b),point(c,d));
		ll res = s1.area() + s2.area() + s3.area() -
			s1.getit(s2).area() - s1.getit(s3).area()
			- s2.getit(s3).area() + s1.getit(s2).getit(s3).area();
		printf("%lld\n", res);
	}
	return 0;

同时,这题还可以用扫描线的方法来做:

https://blog.csdn.net/xianpingping/article/details/83032798

讲的通俗易懂

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;


const int MAXN = 10000;


struct line{
	int ll,rr,h;
	int c;
	line(){};
	
	line(int ll,int rr,int h,int c):ll(ll),rr(rr),h(h),c(c){};

	bool operator<(const line &b){
		return this->h<b.h;
	}
	
};

struct node{
	int ll,rr;
	int cover;
	int sum;
};	
int x_ind[MAXN];
node tree[MAXN*4];
line lines[MAXN];

int N;

void create(int root,int ll,int rr){
	
	tree[root].ll = x_ind[ll];
	tree[root].rr = x_ind[rr];
	tree[root].cover = 0;
	tree[root].sum = 0;
	if(rr - ll == 1) return;
	int mid = (ll+rr)/2;
	create(root*2,ll, mid);
	create(root*2+1,mid,rr);
}

void update(int root , int ll, int rr,int cover){
	if(tree[root].rr<=ll || tree[root].ll>= rr) return;
	
	if(tree[root].ll>=ll && tree[root].rr <= rr){
		tree[root].cover += cover;
			
//		return;
	}
	if(tree[root].rr - tree[root].ll == 1) {
//		tree[root].cover = 0;
		return;
	}
	
	update(root*2 , ll, rr, cover);
	update(root*2+1 ,ll, rr, cover);
	
	
}

int query(int root, int ll, int rr){
	
	if(tree[root].rr<=ll || tree[root].ll>= rr) return 0;
	
	if(tree[root].ll>=ll && tree[root].rr <= rr && tree[root].cover >0){
		return tree[root].rr-tree[root].ll;
	}
	
	if(tree[root].rr - tree[root].ll == 1) return 0;

	int ans =0;
	ans += query(root *2,  ll, rr);
	ans += query(root*2+1,  ll, rr);
	
	return ans; 
} 


int main(){
	
	scanf("%d",&N);
	int j=0;
	int kk=0;
	while(N--){
		memset(tree,0,sizeof(tree));
		
		for(int i=0;i<3;i++){
			int lx,ly,rx,ry;
			scanf("%d%d%d%d",&lx,&ly,&rx,&ry);	
			x_ind[++j] = lx;
			x_ind[++j] = rx;
			lines[++kk] = line(lx,rx,ly,1);
			lines[++kk] = line(lx,rx,ry,-1);
		}
		sort(x_ind+1,x_ind+j+1);
		sort(lines+1,lines+kk+1);
		
		int q=1;
		for(int i=1;i<=j;i++){
			if(x_ind[q] !=x_ind[i])
				x_ind[++q] = x_ind[i]; 
		}
		x_ind[0] = q;
		
		create(1,1,q);
		int ans =0;
		for(int i=1;i<kk;i++){
			
			update(1, lines[i].ll,lines[i].rr,lines[i].c);
			int cover = query(1,x_ind[1],x_ind[q]);
			ans += cover*(lines[i+1].h -lines[i].h);
		} 
		
		printf("%d\n",ans);	
		
	}

	return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值