HDU 1828 - Picture

15 篇文章 0 订阅

 

题目地址: http://acm.hdu.edu.cn/showproblem.php?pid=1828

 

方法: 线段树 + 扫描线

 

用扫描线的思想,很容易就想到,这题扫的主要是外围端点数量。

 

以Y坐标轴作为扫描线,向X轴右方向进行扫描。

 

每次扫描线上的纵向长度改变时(新的出度或者入度),即周长相应地进行变化,于是我们加上这个变化。

 

每次得到端点的数量,这个数量乘以x轴上的跨度,即得到了每次扫描后新增加的横轴周长。

 

关于端点,入度进行记录,出度相应地进行删除。

 

=============================================================================================

PS:

    有了之前一题扫描线的经历,这题看了第一眼就有想法了。

 

    敲得可谓是“轻车熟路”。。。 但最后连sample数据都过不去。。。 囧。。。

 

    一直以为是算法出错。。。 查了半天,发现竟然是细节问题。。。囧。。。

 

           1.  求len长度时,将 r - l + 1 写成了 l - r - 1,导致出现负数。。。又刚好用了abs(),所以很久才发现。。。

           2.  宏定义 rr  写成了 ( v<<1 ) 少加1了。。。

           3.  没有注意看,题目最后说了句:“Please process to the end of file.”。。。 悲剧地只针对一组测试数据去写。。。贡献了一个WA。。。

 

    小错也重要呀~

==============================================================================================

 

#include<iostream>
#include<cstdio>
#include<algorithm>
#define ll (v<<1)
#define rr (v<<1|1)
#define tmid ((l+r)>>1)

using namespace std;

struct Point{
	int x,y1,y2,f;
	Point(){}
	Point(int a,int b,int c,int d){x=a,y1=b,y2=c,f=d;}
	bool friend operator<(Point a,Point b){
		return a.x<b.x;
	}
}p[10100];

int len[80010];
int seg_num[80010];
bool ls[80010],rs[80010];
int tree[80010];

void update(int L,int R,int f,int l,int r,int v){
	if(L<=l && r<=R){
		tree[v]+=f;
	}
	else{
		if(L<=tmid) update(L,R,f,l,tmid,ll);
		if(R>tmid) update(L,R,f,tmid+1,r,rr);
	}
	if(tree[v]>0){
		ls[v]=rs[v]=true;
		seg_num[v]=2;
		len[v]=r-l+1;
	}
	else if(l==r){
		ls[v]=rs[v]=false;
		seg_num[v]=len[v]=0;
	}
	else{
		ls[v]=ls[ll];
		rs[v]=rs[rr];
		seg_num[v]=seg_num[ll]+seg_num[rr];
		if(rs[ll] && ls[rr]) seg_num[v]-=2;
		len[v]=len[ll]+len[rr];
	}
}

int main(){
	int n,i,res,last;
	int x1,y1,x2,y2,tol,a,b,c,d;
	int lm,rm;
	while(~scanf("%d",&n)){
		tol=0;
		lm=10000,rm=-10000;
		while(n--){
			scanf("%d%d%d%d",&a,&b,&c,&d);
			x1=min(a,c),x2=max(a,c);
			y1=min(b,d),y2=max(b,d);
			p[tol++]=Point(x1,y1,y2,1);
			p[tol++]=Point(x2,y1,y2,-1);
			if(lm>y1) lm=y1;
			if(rm<y2) rm=y2;
		}
		sort(p,p+tol);
		res=last=0;
		for(i=0;i<tol;i++){
			if(p[i].y1<p[i].y2) update(p[i].y1,p[i].y2-1,p[i].f,lm,rm-1,1);
			res+=seg_num[1]*(p[i+1].x-p[i].x);
			res+=abs(len[1]-last);
		//	cout<<seg_num[1]<<" "<<len[1]<<endl;
			last=len[1];
		}
		printf("%d\n",res+len[1]);
	}
	return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值