这是测试数据,为了寻找规律而写,具体分析内容请参照http://blog.youkuaiyun.com/chinhape/article/details/9060643
7
-15 0 5 10
-5 8 20 25
15 -4 24 14
0 -6 16 4
2 15 10 22
30 10 36 20
34 0 40 16
//POJ 1177
//N个矩形求总周长
//线段树+离散化+扫描线
//2010年7月21日19:35:45
//Coded By abilitytao
//代码是别人的研究一个星期成果
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
#define MAXN 10010
struct STnode //线段树的节点
{
int l,r;
int len;//区间内代表的长度
int segnum;//区间内被分成的段数,不懂的话再结合代码看看
int cover;//区间被覆盖的次数
int sum;//区间中被覆盖的总长度
bool lcover,rcover;//标记左右端点是否被覆盖,用于合并区间时候统计区间内的离散线段数
STnode()//初始化
{
l = r = 0;
len = segnum = cover = sum = 0;
lcover = rcover = false;
}
};
STnode ST[MAXN*4];//整棵线段树
struct Line
{
int st,ed;//竖边的两个y值
int x;//此条边的x值
bool InOut;//是否为入边
bool operator<(Line o) const//重载小于符号
{
return x<o.x;
}
};
Line Yline[MAXN];//存储竖边
int Index[MAXN];//存储离散后的y值
int cnt=0;
int n;//存储矩形的数目
void Build(int l,int r,int i)//创建线段树
{
ST[i].l=l;
ST[i].r=r;
ST[i].cover=0;
ST[i].len=Index[r]-Index[l];
ST[i].segnum=0;
ST[i].sum=0;
ST[i].lcover=ST[i].rcover=false;
//建立线段的时候进行初始化
if(r-l>1)
{
int mid=(l+r)>>1;
Build(l,mid,i*2);
Build(mid,r,i*2+1);
}
}//build之后的线段树l,r为原来index所在的下标,但是线段树记录长度的信息
void GetLen(int i)//求节点包含的线段总长度
{
if(ST[i].cover>0)
ST[i].sum=ST[i].len;// 如果这条线断是被覆盖的那么总长度为就为这条线断记录的长度
else if(ST[i].r-ST[i].l>1)
ST[i].sum=ST[i*2].sum+ST[i*2+1].sum;//目测这是和计算有覆盖区域有关系的代码【第二次解读】如果ST[i]所在的左右两个下标长度大于一那么线段包的总长度为左右两个节点的线断总长度之合
else
ST[i].sum=0;//如果cover长度为0下标长度为1长度和为0?这是为啥?
}
void GetSegNum(int i)//求该区间所包含的线段数总量(就是含有不想交的线段的条数)
{
if(ST[i].cover>0)
{
ST[i].lcover=ST[i].rcover=true;
ST[i].segnum=1;
}
else if(ST[i].r-ST[i].l>1)
{
ST[i].lcover=ST[i*2].lcover;
ST[i].rcover=ST[i*2+1].rcover;
ST[i].segnum=ST[i*2].segnum+ST[i*2+1].segnum-ST[i*2].rcover*ST[i*2+1].lcover;//这边不太明白segnum-ST[i*2].rcover*ST[i*2+1].lcover这个是和线段有关系?
}
else
{
ST[i].lcover=ST[i].rcover=false;//距离为1的时候为什么肯定不会被覆盖呢??
ST[i].segnum=0;//特殊处理下叶子节点,为什么段数一定为一呢?
}
}
void Insert(int l,int r,int i)//插入一条线段
{
if(ST[i].l==l&&ST[i].r==r)
ST[i].cover++;
else
{
int mid=(ST[i].l+ST[i].r)>>1;
if(r<=mid)
Insert(l,r,i*2);
else if(l>=mid)
Insert(l,r,i*2+1);
else
{
Insert(l,mid,i*2);
Insert(mid,r,i*2+1);
}
}
GetLen(i);//比较难理解的地方在于getlen又没有递归,怎么就更新了从一的值呢,应该从叶子节点开始吧?
GetSegNum(i);
}
void Delete(int l,int r,int i)//删除矩形的右边
{
if(ST[i].l==l&&ST[i].r==r)
ST[i].cover--;
else
{
int mid=(ST[i].l+ST[i].r)>>1;
if(r<=mid)
Delete(l,r,i*2);
else if(l>=mid)
Delete(l,r,i*2+1);
else
{
Delete(l,mid,i*2);
Delete(mid,r,i*2+1);
}
}
GetLen(i);
GetSegNum(i);
//这个后序操作非常精彩!
}
int GetIndex(int x)// 返回x的下标
{
return lower_bound(Index,Index + cnt,x) - Index;//lower_bound函数返回一个元素在容器中的迭代器,数组可以看成特殊的容器,所以这里返回的迭代器就是指针
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
cnt=0;
int i,j,k;
int x1,x2,y1,y2;
for(i=0;i<n;i++)
{
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
Yline[i*2].x=x1;
Yline[i*2+1].x=x2;
Yline[2*i].st=Yline[2*i+1].st=y1;
Yline[2*i].ed=Yline[2*i+1].ed=y2;
Yline[2*i].InOut=true;//标记入边
Yline[2*i+1].InOut=false;
Index[2*i]=y1;
Index[2*i+1]=y2;
}
sort(Index,Index+n*2);;//对y进行排序
sort(Yline,Yline+n*2);//对线段进行排序.排序标准为x
for(int i=1;i<n*2;i++)//Y数组去重
{
if(Index[i]!=Index[i-1])
Index[cnt++]=Index[i-1];
}
Index[cnt++]=Index[2*n-1];//这里很容易错!
Build(0,cnt-1,1);;//用y建立一个线段树
int Ans=0;
int Lsum=0;//上一次记录的长度,画个图很好理解
for(int i=0;i<2*n-1;i++)
{
if(Yline[i].InOut)
Insert(GetIndex(Yline[i].st),GetIndex(Yline[i].ed),1);//getindex用来记录两个y值的位置
else
Delete(GetIndex(Yline[i].st),GetIndex(Yline[i].ed),1);
//画个图还是很好理解下面这两行的
Ans+=ST[1].segnum*(Yline[i+1].x-Yline[i].x)*2;
Ans+=abs(ST[1].sum-Lsum);
Lsum=ST[1].sum;
}
//特殊处理最后一条出边,因为没有下一条竖边了
Delete(GetIndex(Yline[2*n-1].st),GetIndex(Yline[2*n-1].ed),1);
Ans+=abs(ST[1].sum-Lsum);
printf("%d\n",Ans);
}
return 0;
}
//关键理解好这两个函数 GetLen(i); GetSegNum(i);扫描线的精华所在
输出排序后的index值
-6 -4 0 0 4 8 10 10 14 15 16 20 22
=============================
输出排序后的yline值
(-15,0,10) (-5,8,25) (0,-6,4) (2,15,22)(5,0,10) (10,15,22) (15,-4,14) (16,-6,4)
(20,8,25) (24,-4,14) (30,10,20) (34,0,16)(36,10,20)
=============================
输出去重的index值
-6 -4 0 4 8 10 14 15 16 20 22 25
=============================
输出建立后的线段树
(0,11,31,0,0,0,0,0)
(0,5,16,0,0,0,0,0)
(5,11,15,0,0,0,0,0)
(0,2,6,0,0,0,0,0)
(2,5,10,0,0,0,0,0)
(5,8,6,0,0,0,0,0)
(8,11,9,0,0,0,0,0)
(0,1,2,0,0,0,0,0)
(1,2,4,0,0,0,0,0)
(2,3,4,0,0,0,0,0)
(3,5,6,0,0,0,0,0)
=============================
第1次输出值
(0,11,31,1,0,10,0,0)
(0,5,16,1,0,10,0,1)
(5,11,15,0,0,0,0,0)
(0,2,6,0,0,0,0,0)
(2,5,10,1,1,10,1,1)
(5,8,6,0,0,0,0,0)
(8,11,9,0,0,0,0,0)
(0,1,2,0,0,0,0,0)
(1,2,4,0,0,0,0,0)
(2,3,4,0,0,0,0,0)
(3,5,6,0,0,0,0,0)
Ans=30; ST[1].sum=10; Lsum=10 ST[1].segum=1
=============================
第2次输出值
(0,11,31,1,0,25,0,1)
(0,5,16,1,0,10,0,1)
(5,11,15,1,1,15,1,1)
(0,2,6,0,0,0,0,0)
(2,5,10,1,1,10,1,1)
(5,8,6,0,0,0,0,0)
(8,11,9,0,0,0,0,0)
(0,1,2,0,0,0,0,0)
(1,2,4,0,0,0,0,0)
(2,3,4,0,0,0,0,0)
(3,5,6,1,0,2,0,1)
Ans=55; ST[1].sum=25; Lsum=25 ST[1].segum=1
=============================
第3次输出值
(0,11,31,1,0,31,1,1)
(0,5,16,1,0,16,1,1)
(5,11,15,1,1,15,1,1)
(0,2,6,1,1,6,1,1)
(2,5,10,1,1,10,1,1)
(5,8,6,0,0,0,0,0)
(8,11,9,0,0,0,0,0)
(0,1,2,0,0,0,0,0)
(1,2,4,0,0,0,0,0)
(2,3,4,1,1,4,1,1)
(3,5,6,1,0,2,0,1)
Ans=65; ST[1].sum=31; Lsum=31 ST[1].segum=1
=============================
第4次输出值
(0,11,31,1,0,31,1,1)
(0,5,16,1,0,16,1,1)
(5,11,15,1,1,15,1,1)
(0,2,6,1,1,6,1,1)
(2,5,10,1,1,10,1,1)
(5,8,6,1,0,1,0,1)
(8,11,9,1,0,6,1,0)
(0,1,2,0,0,0,0,0)
(1,2,4,0,0,0,0,0)
(2,3,4,1,1,4,1,1)
(3,5,6,1,0,2,0,1)
Ans=71; ST[1].sum=31; Lsum=31 ST[1].segum=1
=============================
第5次输出值
(0,11,31,2,0,27,1,1)
(0,5,16,2,0,12,1,1)
(5,11,15,1,1,15,1,1)
(0,2,6,1,1,6,1,1)
(2,5,10,2,0,6,1,1)
(5,8,6,1,0,1,0,1)
(8,11,9,1,0,6,1,0)
(0,1,2,0,0,0,0,0)
(1,2,4,0,0,0,0,0)
(2,3,4,1,1,4,1,1)
(3,5,6,1,0,2,0,1)
Ans=95; ST[1].sum=27; Lsum=27 ST[1].segum=2
=============================
第6次输出值
(0,11,31,2,0,27,1,1)
(0,5,16,2,0,12,1,1)
(5,11,15,1,1,15,1,1)
(0,2,6,1,1,6,1,1)
(2,5,10,2,0,6,1,1)
(5,8,6,0,0,0,0,0)
(8,11,9,0,0,0,0,0)
(0,1,2,0,0,0,0,0)
(1,2,4,0,0,0,0,0)
(2,3,4,1,1,4,1,1)
(3,5,6,1,0,2,0,1)
Ans=115; ST[1].sum=27; Lsum=27ST[1].segum=2
=============================
第7次输出值
(0,11,31,1,0,31,1,1)
(0,5,16,1,0,16,1,1)
(5,11,15,1,1,15,1,1)
(0,2,6,1,1,6,1,1)
(2,5,10,1,1,10,1,1)
(5,8,6,1,0,4,1,0)
(8,11,9,0,0,0,0,0)
(0,1,2,0,0,0,0,0)
(1,2,4,1,1,4,1,1)
(2,3,4,1,1,4,1,1)
(3,5,6,1,0,2,0,1)
Ans=121; ST[1].sum=31; Lsum=31ST[1].segum=1
=============================
第8次输出值
(0,11,31,1,0,29,0,1)
(0,5,16,1,0,14,0,1)
(5,11,15,1,1,15,1,1)
(0,2,6,1,0,4,0,1)
(2,5,10,1,1,10,1,1)
(5,8,6,1,0,4,1,0)
(8,11,9,0,0,0,0,0)
(0,1,2,0,0,0,0,0)
(1,2,4,1,1,4,1,1)
(2,3,4,0,0,0,0,0)
(3,5,6,1,0,2,0,1)
Ans=131; ST[1].sum=29; Lsum=29ST[1].segum=1
=============================
第9次输出值
(0,11,31,1,0,18,0,0)
(0,5,16,1,0,14,0,1)
(5,11,15,1,0,4,1,0)
(0,2,6,1,0,4,0,1)
(2,5,10,1,1,10,1,1)
(5,8,6,1,0,4,1,0)
(8,11,9,0,0,0,0,0)
(0,1,2,0,0,0,0,0)
(1,2,4,1,1,4,1,1)
(2,3,4,0,0,0,0,0)
(3,5,6,0,0,0,0,0)
Ans=150; ST[1].sum=18; Lsum=18ST[1].segum=1
=============================
第10次输出值
(0,11,31,0,0,0,0,0)
(0,5,16,0,0,0,0,0)
(5,11,15,0,0,0,0,0)
(0,2,6,0,0,0,0,0)
(2,5,10,0,0,0,0,0)
(5,8,6,0,0,0,0,0)
(8,11,9,0,0,0,0,0)
(0,1,2,0,0,0,0,0)
(1,2,4,0,0,0,0,0)
(2,3,4,0,0,0,0,0)
(3,5,6,0,0,0,0,0)
Ans=168; ST[1].sum=0; Lsum=0 ST[1].segum=0
=============================
第11次输出值
(0,11,31,1,0,10,0,0)
(0,5,16,0,0,0,0,0)
(5,11,15,1,0,10,1,0)
(0,2,6,0,0,0,0,0)
(2,5,10,0,0,0,0,0)
(5,8,6,1,1,6,1,1)
(8,11,9,1,0,4,1,0)
(0,1,2,0,0,0,0,0)
(1,2,4,0,0,0,0,0)
(2,3,4,0,0,0,0,0)
(3,5,6,0,0,0,0,0)
Ans=186; ST[1].sum=10; Lsum=10ST[1].segum=1
=============================
第12次输出值
(0,11,31,1,0,20,0,0)
(0,5,16,1,0,10,0,1)
(5,11,15,1,0,10,1,0)
(0,2,6,0,0,0,0,0)
(2,5,10,1,1,10,1,1)
(5,8,6,1,2,6,1,1)
(8,11,9,1,0,4,1,0)
(0,1,2,0,0,0,0,0)
(1,2,4,0,0,0,0,0)
(2,3,4,0,0,0,0,0)
(3,5,6,0,0,0,0,0)
Ans=200; ST[1].sum=20; Lsum=20ST[1].segum=1
=============================
第13次输出值
(0,11,31,1,0,16,0,0)
(0,5,16,1,0,10,0,1)
(5,11,15,1,0,6,1,0)
(0,2,6,0,0,0,0,0)
(2,5,10,1,1,10,1,1)
(5,8,6,1,1,6,1,1)
(8,11,9,0,0,0,0,0)
(0,1,2,0,0,0,0,0)
(1,2,4,0,0,0,0,0)
(2,3,4,0,0,0,0,0)
(3,5,6,0,0,0,0,0)
Ans=212; ST[1].sum=16; Lsum=16ST[1].segum=1
=============================
228