这题看了好久,先看了陈宏的论文,然后关于测度,连续段数的地方没看明白,后来又找了源代码看,确实自己很难写出来比较简洁的代码,对核心部分还是不够理解。
题解:首先离散化,没的说,然后建线段树,要先unique一下y数组,然后根据扫描线,insert,或者remove,并对维护过的点update_m,update_line。
最精髓的部分或许是在论文里没有着重提到的如何计算轮廓线,其实只需一次扫描,用测度m来计算纵向(扫描线上的竖直轮廓线),用连续段数来计算横向(水平轮廓线),很关键,这点一直卡着,好久才明白。
#include <iostream>
#include <fstream>
#include <algorithm>
using namespace std;
#define LEN 10000
struct Node {
int left,right;
int Count;
int line;
int lbd,rbd;
int m; //具体的y
};
struct ScanLine {
int x,y1,y2;
int flag;
};
Node node[LEN*4];
ScanLine scan[LEN];
int y[LEN];
bool cmp(ScanLine a,ScanLine b)
{
if (a.x==b.x)
return a.flag>b.flag; //special
return a.x<b.x;
}
void build(int l,int r,int i)
{
node[i].left=l;
node[i].right=r;
node[i].Count= node[i].m =node[i].line =0;
if (r-l>1) {
int middle=(l+r)/2;
build(l,middle,2*i+1);
build(middle,r,2*i+2); //array build
}
}
void update_m(int i)
{
if (node[i].Count)
node[i].m=y[node[i].right]-y[node[i].left];
else if (node[i].right-node[i].left==1)
node[i].m=0;
else {
node[i].m=node[2*i+1].m+node[2*i+2].m;
}
}
void update_line(int i)
{
if (node[i].Count){
node[i].lbd =node[i].rbd =node[i].line =1;
}
else if (node[i].right-node[i].left==1){
node[i].lbd =node[i].rbd =node[i].line =0;
}
else {
node[i].lbd= node[2*i+1].lbd;
node[i].rbd= node[2*i+2].rbd;
node[i].line = node[2*i+1].line+node[2*i+2].line-
node[2*i+1].rbd*node[2*i+2].lbd;
}
}
void Insert(int l,int r,int i)
{
if (y[node[i].left]>=l && y[node[i].right]<=r)
node[i].Count++;
else if (node[i].right-node[i].left==1)
return ;
else {
int middle=(node[i].left+node[i].right)/2;
if (r<=y[middle])
Insert(l,r,2*i+1);
else if (l>=y[middle])
Insert(l,r,2*i+2);
else {
Insert(l,r,2*i+1);
Insert(l,r,2*i+2);
}
}
update_m(i);
update_line(i);
}
void Remove(int l,int r,int i)
{
if (y[node[i].left]>=l && y[node[i].right]<=r)
node[i].Count--;
else if (node[i].right-node[i].left==1)
return ;
else {
int middle=(node[i].left+node[i].right)/2;
if (r<=y[middle])
Remove(l,r,2*i+1);
else if (l>=y[middle])
Remove(l,r,2*i+2);
else {
Remove(l,r,2*i+1);
Remove(l,r,2*i+2);
}
}
update_m(i);
update_line(i);
}
int main()
{
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
int n;
scanf("%d",&n);
int x1,x2,y1,y2;
int i=0;
while (n--){
scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
scan[i].x=x1;
scan[i].y1=y1;
scan[i].y2=y2;
scan[i].flag=1;
y[i++]=y1;
scan[i].x=x2;
scan[i].y1=y1;
scan[i].y2=y2;
scan[i].flag=0;
y[i++]=y2;
}
sort(y,y+i);
sort(scan,scan+i,cmp);
int unique_count=unique(y,y+i)-y;
build(0,unique_count-1,0);
int perimeter=0;
int now_m=0;
int now_line=0;
for (int j=0;j<i;j++){
if (scan[j].flag)
Insert(scan[j].y1,scan[j].y2,0);
else
Remove(scan[j].y1,scan[j].y2,0);
if (j)
perimeter+=2*now_line*(scan[j].x-scan[j-1].x);
perimeter += abs(node[0].m-now_m);
now_m=node[0].m;
now_line=node[0].line;
}
printf("%d\n",perimeter);
return 0;
}