hdu1828 Picture (线段树+扫描线)

题目:

给n个矩形求周长并。

分析:

唯一需要注意的地方就是,对线段排序的时候不能单纯只考虑高度,还要考虑是上边还是下边。如果有一个上边和一个下边高度一样,那么应该让上边在前下边在后。

代码:

#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 = 1e5 + 5;
const int BASE = 10001;
struct Edge {
	int x1, x2, y;
	int f;
	Edge () {}
	Edge (int x1, int x2, int y, int f): x1(x1), x2(x2), y(y), f(f) {}
	bool operator <(const Edge &edge) const {
		if(y != edge.y)	return y < edge.y;
		return f < edge.f;
	}
} e1[MAXN << 1], e2[MAXN << 1];
int n, cnt;
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] = r + 1 - 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 solve(Edge e[]) {
	int ret = 0, last = 0;
	for (int i = 1; i <= cnt; i++) {
		T.update(e[i].x1, e[i].x2-1, 1, 1, 20000, e[i].f);
		ret += abs(T.tree[1] - last);
		last = T.tree[1];
	}
	return ret;
}
int main() {
	// freopen("1.txt","r",stdin);
	ios::sync_with_stdio(false);
	while (cin >> n) {
		int x1, x2, y1, y2;
		cnt = 0;
		for (int i = 0; i < n; i++) {
			cin >> x1 >> y1 >> x2 >> y2;
			e1[++cnt] = Edge(x1+BASE, x2+BASE, y1+BASE, -1);
			e2[cnt] = Edge(y1+BASE,y2+BASE,x1+BASE,-1);
			e1[++cnt] = Edge(x1+BASE, x2+BASE, y2+BASE, 1);
			e2[cnt] = Edge(y1+BASE,y2+BASE,x2+BASE,1);
		}
		sort(e1 + 1, e1 + 1 + cnt);
		sort(e2 + 1, e2 + 1 + cnt);
		int ans = 0;
		T.build();	
		ans += solve(e1);
		T.build();
		ans += solve(e2);
		cout << ans << "\n";
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值