hdu1542 Atlantis (线段树+扫描线)

题目:

给n个矩形,求矩形的面积并。n <= 100

分析:

扫描线求面积并模板题。
需要注意的是,线段树记录的不是点,而是边。数轴上若有 1-n 共 n 个点,则会切出 n - 1 条不能再切分的小线段,将这些线段从左至右依次标号为 1 - (n-1)。线段树的每个叶子节点就表示一条小线段。
线段树避免同一段重复加的方法是:对于某一段,如果tag[rt] > 0,则不通过子树来更新值,而是直接计算这一段的值。这样就可避免重复。

代码:

#include <bits/stdc++.h>
using namespace std;
#define ms(a,b) memset(a,b,sizeof(a))
#define lson rt*2,l,(l+r)/2
#define rson rt*2+1,(l+r)/2+1,r
typedef unsigned long long ull;
typedef long long ll;
const int MAXN = 300;
const double EPS = 1e-8;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
struct Edge {
	double x1, x2, y;
	int f;
	Edge () {}
	Edge (double x1, double x2, double y, int f): x1(x1), x2(x2), y(y), f(f) {}
	bool operator <(const Edge &edge) const{
		return y < edge.y;
	}
} e[MAXN << 1];
int n;
double x[MAXN];
struct Seg_tree {
	double tree[MAXN<<2];
	int tag[MAXN<<2]; 
	void build(){
		ms(tree,0);	ms(tag,0);
	}
	void pushup(int rt,int l,int r){
		if(tag[rt]) tree[rt] = x[r+1] - x[l];
		else if(l==r) tree[rt] = 0;
		else tree[rt] = tree[rt<<1]+tree[rt<<1|1];
	}
	void update(int L,int R, int rt,int l,int r,int t){
		if(L<=l && R>=r){
			tag[rt] += t;
			pushup(rt,l,r);
			return;
		}
		if(L <= (l+r)/2) update(L,R,lson,t);
		if(R > (l+r)/2)	update(L,R,rson,t);
		pushup(rt,l,r);
	}
}T;

int main() {
	// freopen("1.txt","r",stdin);
	ios::sync_with_stdio(false);
	int Case = 0;
	while (cin >> n && n) {
		double x1, x2, y1, y2;
		int cnt = 0;
		for (int i = 0; i < n; i++) {
			cin >> x1 >> y1 >> x2 >> y2;
			e[++cnt] = Edge(x1, x2, y1, -1);
			x[cnt] = x1;
			e[++cnt] = Edge(x1, x2, y2, 1);
			x[cnt] = x2;
		}
		sort(e + 1, e + 1 + cnt);
		sort(x + 1, x + 1 + cnt);
		int m = unique(x + 1, x + 1 + cnt) - x - 1;
		T.build();
		double ans = 0;
		for(int i=1;i<=cnt-1;i++){
			int l = lower_bound(x+1,x+1+m,e[i].x1) - x;
			int r = lower_bound(x+1,x+1+m,e[i].x2) - x - 1;
			T.update(l,r,1,1,m-1,e[i].f);
			ans += T.tree[1] * (e[i+1].y - e[i].y);
		}
		cout << "Test case #" << ++Case << "\n" << fixed << setprecision(2) << "Total explored area: " << ans << "\n\n";
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值