A number of rectangular posters, photographs and other pictures of the
same shape are pasted on a wall. Their sides are all vertical or
horizontal. Each rectangle can be partially or totally covered by the
others. The length of the boundary of the union of all rectangles is
called the perimeter.
Write a program to calculate the perimeter. An example with 7 rectangles is shown in Figure 1.
The vertices of all rectangles have integer coordinates.
Input
Your program is to read from standard input. The first line
contains the number of rectangles pasted on the wall. In each of the
subsequent lines, one can find the integer coordinates of the lower left
vertex and the upper right vertex of each rectangle. The values of
those coordinates are given as ordered pairs consisting of an
x-coordinate followed by a y-coordinate.
0 <= number of rectangles < 5000
All coordinates are in the range [-10000,10000] and any existing rectangle has a positive area.
Please process to the end of file.
Output
Your program is to write to standard output. The output must
contain a single line with a non-negative integer which corresponds to
the perimeter for the input rectangles.
题意:
扫描图形边界周长。
#include
#include
#include
#include
#include
#include
#include
using namespace std; //扫描线模版题; 只需要理解好原理就能想到,分别对x,y进行扫描;
#define ml root<<1
#define mr root<<1|1
const int N=1e5+55;
int pox[N],poy[N]; //分别记录x,y,轴离散化后的坐标值;
struct nodey{ //存线段;
int x1,x2,y;
int val;
}mpy[N];
struct nodex{
int y1,y2,x;
int val;
}mpx[N];
struct nod{
int sum;
int val;
}rt[N];
bool cmp_y(nodey a, nodey b) //将y轴按升序排列,对y轴进行扫描;
{
return a.y<b.y;
}
bool cmp_x(nodex a, nodex b) //将x轴按升序排列,对x轴进行扫描:
{
return a.x<b.x;
}
void build_tree() //初始化树;
{
for(int i=0;i<N;++i){
rt[i].sum=0;
rt[i].val=0;
}
}
void up_d(int root, int l, int r, bool k) //利用线段树维护每一段的长度;
{
if(k){ //k为ture时对y进行扫描,false对x进行扫描;
if(rt[root].val) rt[root].sum=pox[r+1]-pox[l]; //直接记录区间长度;
else if(l==r) rt[root].sum=0; //对没有了的区间进行清零;
else rt[root].sum=rt[ml].sum+rt[mr].sum; //上传数据+清零,维护线段树;
}
else{ //同上;
if(rt[root].val) rt[root].sum=poy[r+1]-poy[l];
else if(l==r) rt[root].sum=0;
else rt[root].sum=rt[ml].sum+rt[mr].sum;
}
}
void update(int root, int l, int r, int s, int t, int val, bool k) //线段树基本操作,遍历树;
{
if(l==s&&r==t){
rt[root].val+=val;
up_d(root,l,r,k);
return ;
}
int mid=(l+r)>>1;
if(mid>=t) update(ml,l,mid,s,t,val,k);
else if(mid<s) update(mr,mid+1,r,s,t,val,k);
else update(ml,l,mid,s,mid,val,k),update(mr,mid+1,r,mid+1,t,val,k);
up_d(root,l,r,k);
}
int main()
{
int n,i,l,r;
int x1,x2,y1,y2;
while(scanf("%d",&n)!=EOF){
int cnt=1,tx=1,ty=1;
for(i=1;i<=n;++i){
scanf("%d%d%d%d",&x1,&y1,&x2,&y2); //录入数据;
mpy[cnt]={x1,x2,y1,1};
mpx[cnt]={y1,y2,x1,1};
pox[cnt]=x1;
poy[cnt++]=y1;
mpy[cnt]={x1,x2,y2,-1};
mpx[cnt]={y1,y2,x2,-1};
pox[cnt]=x2;
poy[cnt++]=y2;
}
sort(pox+1,pox+cnt);
sort(poy+1,poy+cnt);
for(i=2;i<cnt;++i){ //离散化处理;
if(pox[i]!=pox[i-1]) pox[++tx]=pox[i];
if(poy[i]!=poy[i-1]) poy[++ty]=poy[i];
}
sort(mpy+1,mpy+cnt,cmp_y);
sort(mpx+1,mpx+cnt,cmp_x);
int temp=0;
long long ans=0;
build_tree();
for(i=1;i<cnt;++i){ //向上扫描Y轴;
l=lower_bound(pox+1,pox+tx+1,mpy[i].x1)-pox;
r=lower_bound(pox+1,pox+tx+1,mpy[i].x2)-pox;
update(1,1,tx,l,r-1,mpy[i].val,true);
ans+=abs(rt[1].sum-temp); //本次的有效线段为这次扫描的线-上次线的绝对值;
temp=rt[1].sum;
}
build_tree();
temp=0;
for(i=1;i<cnt;++i){ //向右扫描X轴;
l=lower_bound(poy+1,poy+ty+1,mpx[i].y1)-poy;
r=lower_bound(poy+1,poy+ty+1,mpx[i].y2)-poy;
update(1,1,ty,l,r-1,mpx[i].val,false);
ans+=abs(rt[1].sum-temp);
temp=rt[1].sum;
}
printf("%lld\n",ans);
}
return 0;
}