POJ3277(线段树+扫描线/矩形面积并)

题意:

给n个建筑,每个建筑的起点终点和高度,求所有建筑从侧面看的面积

思路:

扫描线法

从下往上扫描,把每个建筑的底部看做一个边,其高度为0,1来记录下边。
剩下的就是矩形面积并了。

#include 
#include 
#include 
#define lson l, mid, root<<1
#define rson mid, r, root<<1|1
using namespace std;
const int INF = 0x3f3f3f3f;
typedef long long LL;
const int maxn = 80000+5;

struct Edge{
	int l, r, h;
	int p;
	Edge(){}
	Edge(int a, int b, int c, int d):l(a),r(b),h(c),p(d){} 
	bool operator < (const Edge& rhs) const{
		return h < rhs.h;
	}
}B[maxn];
struct Node{
	int cover, len;
}Tree[maxn<<2];
int X[maxn];

void Stree_build(int l, int r, int root){
	Tree[root].cover = Tree[root].len = 0;
	if(l+1 == r) return;
	int mid = (l+r) >> 1;
	Stree_build(lson);
	Stree_build(rson);
}
void push_up(int l, int r, int root){
	if(Tree[root].cover > 0) Tree[root].len = X[r] - X[l];
	else if(l+1 == r) Tree[root].len = 0;
	else Tree[root].len = Tree[root<<1].len + Tree[root<<1|1].len;
}
void update(int la, int rb, int l, int r, int root, int val){
	if(la > r||rb < l) return;
	if(la <= l&&rb >= r){
		Tree[root].cover+= val;
		push_up(l, r, root);
		return;
	}
	if(l+1 == r) return;
	int mid = (l+r) >> 1;
	if(la <= mid)  update(la, rb, lson, val);
	if(rb > mid)  update(la, rb, rson, val);
	push_up(l, r, root);
}

int main()
{
	//freopen("in.txt","r",stdin);
	int n, a,b,c;
	while(scanf("%d",&n) == 1&&n){
		int tot = 0;
		for(int i = 1; i <= n; ++i) {
			scanf("%d%d%d", &a, &b, &c);
			B[++tot] = Edge(a, b, 0, 1);
			X[tot] = a;
			B[++tot] = Edge(a, b, c, -1);
			X[tot] = b;
		}
		sort(B+1, B+tot+1);
		sort(X+1, X+tot+1);
		
		int k = 1;
		for(int i = 2; i <= tot; ++i) if(X[i] != X[i-1]) X[++k] = X[i];
		Stree_build(1, k, 1);
		
		LL ans = 0;
		for(int i = 1; i < tot; ++i){
			int l = lower_bound(X+1, X+k+1, B[i].l) - X;
			int r = lower_bound(X+1, X+k+1, B[i].r) - X;
			
			//printf("l = %d, r = %d, len = %d\n", l, r,Tree[1].len);
			update(l, r, 1, k, 1, B[i].p);
			ans+= (LL)(B[i+1].h - B[i].h) * Tree[1].len;
		}
		printf("%lld\n", ans);
	}

	return 0;
}

单调队列:
#include 
#include 
#include 
#include 

using namespace std;
const int INF = 0x3f3f3f3f;
typedef long long LL;
const int maxn = 40000+5;

struct Building{
	int l, r, h;
}B[maxn];

struct Node{
	int x, id;
	bool operator < (const Node& rhs) const{
		if(x != rhs.x) return x < rhs.x;
		return id < rhs.id;
	}
}nodes[maxn<<1];

struct cmp{
	bool operator()(const Node& a, const Node& b){
		if(B[a.id].h != B[b.id].h) return B[a.id].h < B[b.id].h;
		return a.id < b.id;
	}
};
priority_queue, cmp> Q;
int inq[maxn];

int main()
{
	//freopen("in.txt","r",stdin);
	int n;
	while(scanf("%d",&n) == 1&&n){
		int tot = 0;
		for(int i = 0; i < n; ++i){
			scanf("%d%d%d", &B[i].l,&B[i].r,&B[i].h);
			nodes[tot].x = B[i].l; nodes[tot++].id = i;
			nodes[tot].x = B[i].r; nodes[tot++].id = i;
		}
		sort(nodes, nodes+tot);
		memset(inq, 0, sizeof(inq));
		int last = 0;
		LL ans = 0;
		for(int i = 0; i < tot; ++i){
			if(!Q.empty()) ans+= (LL)(nodes[i].x - last) * B[Q.top().id].h;
			last = nodes[i].x;
			if(0 == inq[nodes[i].id]){
				Q.push(nodes[i]);
				inq[nodes[i].id] = 1;
			}
			else inq[nodes[i].id] = 0;
			while(!Q.empty()&&0 == inq[Q.top().id]) Q.pop();
		}
		printf("%lld\n", ans);
	}

	return 0;
}



你可能感兴趣的:(矩形面积并,单调队列,线段树,单调栈or单调队列)