Picture HDU - 1828(线段树,扫描线)

Picture

题目链接:HDU - 1828

题意:有多个矩形重叠在一起,求出重叠后的图形的周长,如下图,阴影部分是若干矩形重叠后的部分,彩色线条是重叠后图形的边框,即周长,左侧是矩形的坐标:

当我们用扫描线由下向上扫的时候每次变化的长度之后就是上下底线的长度之后,然后就剩下竖线的长度和了;

竖线的长度和是扫描线移动长度*竖线条数;移动长度就是上下两根线间隔,关键是求条数;

我们用线段树维护时,[l, r]区间的竖线条数分三种情况:

一:[l, r]被完全覆盖,此时由且只有2条竖线;

二:l=r此时是叶节点为0;

三:[l, r]被覆盖部分,那么此区间的竖线条数是子区间竖线条数之和,但是当左子区间的右边与由区间的左边重叠时,父区间竖线条数要减少两条;

用由下向上的扫描线是正确的,但是改成由左到右的扫描线就WA了,一直不明所以,若有朋友了解望指出!

#include <bits/stdc++.h>
using namespace std;
const int maxn=100010;
struct Line{
	int y, x1, x2, v;
	Line(){}
	Line(int y0, int x10, int x20, int v0){
		y=y0, x1=x10, x2=x20, v=v0;
	}
	bool operator < (const Line &p) const{
		return y<p.y;
	}
}line[maxn];
struct node{
	int l, r, v, len, s, ls, rs;
}tr[maxn<<3];
void build(int m, int l, int r){
	tr[m].l=l;
	tr[m].r=r;
	tr[m].len=tr[m].v=tr[m].s=tr[m].ls=tr[m].rs=0;
	if(l==r) return;
	int mid=(l+r)>>1;
	build(m<<1, l, mid);
	build(m<<1|1, mid+1, r);
}
void pushup(int m){
	if(tr[m].v){
		tr[m].len=tr[m].r+1-tr[m].l;
		tr[m].s=1;
		tr[m].ls=tr[m].rs=1;
	}else if(tr[m].l==tr[m].r){
		tr[m].len=tr[m].s=tr[m].ls=tr[m].rs=0;
	}else{
		tr[m].len=tr[m<<1].len+tr[m<<1|1].len;
		tr[m].ls=tr[m<<1].ls;
		tr[m].rs=tr[m<<1|1].rs;
		tr[m].s=tr[m<<1].s+tr[m<<1|1].s-(tr[m<<1].rs&tr[m<<1|1].ls);
	}
}
void updata(int m, int l, int r, int v){
	if(tr[m].l==tr[m].r){
		tr[m].v+=v;
		pushup(m);
		return;
	}
	int mid=(tr[m].r+tr[m].l)>>1;
	if(r<=mid) updata(m<<1, l, r, v);
	else if(l>mid) updata(m<<1|1, l, r, v);
	else{
		updata(m<<1, l, mid, v);
		updata(m<<1|1, mid+1, r, v);
	}
	pushup(m);
}
int  main(){
	int n, x1, x2, y1, y2;
	while(~scanf("%d", &n)){
		if(n==0){
			printf("0\n");
			continue;
		}
		int L=maxn, R=-maxn, cnt=0;
		for(int i=0; i<n; i++){
			scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
			line[++cnt]=Line(y1, x1, x2, 1);
			line[++cnt]=Line(y2, x1, x2, -1);
			L=min(L, x1);
			R=max(R, x2);
		}
		build(1, L, R);
		sort(line+1, line+1+cnt);
		int ans=0, prelen=0;
		for(int i=1; i<=cnt; i++){
			int l=line[i].x1, r=line[i].x2-1, v=line[i].v;
			updata(1, l, r, v);
			ans+=abs(prelen-tr[1].len);
			prelen=tr[1].len;
			if(i!=cnt) ans+=2*tr[1].s*(line[i+1].y-line[i].y);
		}
		printf("%d\n", ans);
	}
	return 0;
}
扫描二维码关注公众号,回复: 2301089 查看本文章

猜你喜欢

转载自blog.csdn.net/sirius_han/article/details/81091674
今日推荐