题目大意:给出n个矩形,求他们的周长。
思路:这个是扫描线求多矩形周长的应用,跟面积一样对x轴进行扫描。
不同的是线段树中维护的东西多了一样:区间内高的数量。
对于这个周长,宽的高度等于这一次扫描的结果跟上一次的结果的绝对值。
高等于num* 2 *两条两条线的差值。
代码包括了离散化,非常的规范。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>
using namespace std;
const int maxn = 5000+10;
double xx[maxn<<1];
struct Edge
{
double l,r,h;
int inout;
Edge(){}
Edge(double x1, double x2, double y, double in):l(x1),r(x2),h(y),inout(in){}
} e[maxn<<1];
bool cmp(Edge a, Edge b)
{
return a.h<b.h;
}
struct Tree
{
int l,r;
int lc,rc;
int lazy;
double len;
int num;
int mid()
{
return (l+r)>>1;
}
}tr[maxn <<2];
void pushup(int now)
{
if(tr[now].lazy)
{
tr[now].len = xx[tr[now].r+1]-xx[tr[now].l];
tr[now].lc = 1,tr[now].rc = 1,tr[now].num = 1;
}
else if(tr[now].l == tr[now].r)
{
tr[now].len = 0;
tr[now].num = 0;
tr[now].lc = 0, tr[now].rc = 0;
}
else
{
tr[now].lc = tr[now<<1].lc, tr[now].rc = tr[now<<1|1].rc;
tr[now].len = tr[now<<1].len + tr[now<<1|1].len;
tr[now].num = tr[now<<1].num+ tr[now<<1|1].num -(tr[now<<1].rc & tr[now<<1|1].lc);
}
}
void build(int now, int l, int r)
{
tr[now].l = l, tr[now].r = r;
tr[now].lazy = 0, tr[now].lc = 0,tr[now].rc = 0;
tr[now].num = 0,tr[now].len = 0;
if(tr[now].l == tr[now].r)
return;
int mid = tr[now].mid();
build(now<<1,l,mid);
build(now<<1|1, mid+1,r);
}
void update(int now, int l, int r,int val)
{
if(tr[now].l>=l && tr[now].r<=r)
{
tr[now].lazy+=val;
pushup(now);
return;
}
int mid = tr[now].mid();
if(mid>=r)update(now<<1,l,r,val);
else if(mid<l)update(now<<1|1,l,r,val);
else
{
update(now<<1,l,mid,val);
update(now<<1|1,mid+1,r,val);
}
pushup(now);
}
int main()
{
int n;
scanf("%d",&n);
int cnt = 0;
for(int i = 0;i<n;i++)
{
double x1,x2,y1,y2;
scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
xx[++cnt] = x1;
e[cnt] = Edge(x1,x2,y1,1);
xx[++cnt] = x2;
e[cnt] = Edge(x1,x2,y2,-1);
}
sort(xx+1,xx+1+cnt);
sort(e+1,e+1+cnt,cmp);
int len = unique(xx+1,xx+1+cnt)-(xx+1);
build(1,1,len);
double perimeter= 0;
double last = 0;
for(int i = 1;i<=cnt;i++)
{
int l = lower_bound(xx+1,xx+1+len,e[i].l)-xx;
int r = lower_bound(xx+1,xx+1+len,e[i].r)-xx-1;
update(1,l,r,e[i].inout);
perimeter +=tr[1].num*2*(e[i+1].h-e[i].h);//高;
perimeter += fabs(last - tr[1].len);//宽
last = tr[1].len;
}
printf("%.0f\n",perimeter);
return 0;
}