N - Picture POJ - 1177(矩形周长并 + 线段树 + 离散化)

本代码采用的是横向扫描一遍和纵向扫描一遍来得到最终的结果,核心部分就是求举行周长并,当然也要对线段树比较熟悉才行,毕竟矩形周长并,面积并,面积交都要用到线段树来计算。说说求举行周长并的过程吧,我们先计算横向线段的长度,把所有坐标的y轴坐标按照升序排列,扫描线从y的最小值依次向上扫描,求出每次扫描所覆盖的长度,与上一次长度做差得到其绝对值(这个值不需要加到线段树中去),加到最终的答案中去。横向纵向都来一遍就得出最终的答案了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 10020;
int n;
int all[2][maxn], tree[maxn << 2], lazy[maxn << 2];

struct rec
{
	int l, r;
	int order, val;
	void setval(int a, int b, int c, int d)
	{
		l = a;
		r = b;
		order = c;
		val = d;
	}
	friend bool operator < (rec a, rec b)
	{
		return a.order < b.order;
	}
}a[2][maxn];

void update(int L, int R, int val, int l, int r, int rt, int flag)
{
	if(l >= L && r <= R)
	{
        lazy[rt] += val;
        if(lazy[rt])
            tree[rt] = all[flag][r + 1] - all[flag][l];
        else if(l == r)
            tree[rt] = 0;
        else
            tree[rt] = tree[rt << 1] + tree[rt << 1 | 1];
		return ;
	}
	int m = (l + r) / 2;
	if(m >= L)
		update(L, R, val, l, m, rt << 1, flag);
	if(m < R)
		update(L, R, val, m + 1, r, rt << 1 | 1, flag);
	if(lazy[rt])
            tree[rt] = all[flag][r + 1] - all[flag][l];
    else
            tree[rt] = tree[rt << 1] + tree[rt << 1 | 1];
}

int main()
{
    //freopen("in.txt", "r", stdin);
	cin >> n;
	int m[4];
	int x1, x2, y1, y2;
	rec temp;
	for(int i = 1; i <= n; ++ i)
	{
		scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
		all[0][i] = x1, all[0][i + n] = x2;
		all[1][i] = y1, all[1][i + n] = y2;
		temp.setval(x1, x2, y1, 1);
		a[0][i] = temp;
		temp.setval(x1, x2, y2, -1);
		a[0][i + n] = temp;
		temp.setval(y1, y2, x1, 1);
		a[1][i] = temp;
		temp.setval(y1, y2, x2, -1);
		a[1][i + n] = temp;
	}
	n <<= 1;

	sort(all[0] + 1, all[0] + 1 + n);
	m[0] = unique(all[0] + 1, all[0] + 1 + n) - all[0] - 1;
	sort(all[1] + 1, all[1] + 1 + n);
	m[1] = unique(all[1] + 1, all[1] + 1 + n) - all[1] - 1;

	sort(a[0] + 1, a[0] + 1 + n);
	sort(a[1] + 1, a[1] + 1 + n);

	int ans = 0;
	for(int i = 0; i <= 1; ++ i)
	{
		int last = 0;
		memset(tree, 0, sizeof(tree));
		memset(lazy, 0, sizeof(lazy));
		for(int j = 1; j <= n; ++ j)
		{
			int l = lower_bound(all[i] + 1, all[i] + 1 + m[i], a[i][j].l) - all[i];
			int r = lower_bound(all[i] + 1, all[i] + 1 + m[i], a[i][j].r) - all[i];
			update(l, r - 1, a[i][j].val, 1, m[i], 1, i);      ///范围是l到r-1,是因为线段树存的其实是点,要存区间的的话得稍加转换。
			ans += abs(tree[1] - last);
			last = tree[1];
		}
	}
	cout << ans << endl;
	return 0;
}


猜你喜欢

转载自blog.csdn.net/aqa2037299560/article/details/82945148