问题描述:给定n条线段,求这n条线段所覆盖的总长度。
思路:首先求出n 条线段的最小左端点Lmin和最大右端点Rmax,以这个界限生成线段树如[Lmin,Rmax]=[1,10];
[1,10]
1
[1,5] [5,10]
2 3
[1,3] [3,5] [5,7] [7,10]
4 5 6 7
[1,2] [2,3] [3,4] [4,5] [5,6] [6,7] [7,8] [8,10]
8 9 10 11 12 13 14 15
[8,9] [9,10]
30 31
因为生成的线段树是二叉树,所以,各结点的编号符合:父:num,子:num*2,num*2+1;
这里我用数组LT[8001]来实现线段树的存储;
代码如下:
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
struct LineTree{
int l,r,mid,cover;
};
struct Line{
int ll,rr;
};
LineTree LT[8001];
void make(int left,int right,int num) //线段树的构建
{
LT[num].l=left;
LT[num].r=right;
LT[num].mid=(left+right)/2;
LT[num].cover=0;
if(left+1!=right)
{
make(left,LT[num].mid,num*2);
make(LT[num].mid,right,num*2+1);
}
}int cmp(const void *a,const void *b)
{
Line *c=(Line*)a;
Line *d=(Line*)b;
return (c->ll)-(d->ll);
}void cover(int l,int r,int num)//线段的插入(覆盖情况)
{
if(LT[num].cover==0)
{
if(l==LT[num].l&&r==LT[num].r)
{
LT[num].cover=1;
return;
}
if(r<=LT[num].mid)
{
cover(l,r,num*2);
}
else if(l>=LT[num].mid)
{
cover(l,r,num*2+1);
}
else
{
cover(l,LT[num].mid,num*2);
cover(LT[num].mid,r,num*2+1);
}
}
}int count(int num) //对覆盖线段的长度进行统计
{
if(LT[num].cover==1)
{
return LT[num].r-LT[num].l;
}
else if(LT[num].r-LT[num].l==1)
{
return 0;
}
return count(num*2)+count(num*2+1);
}
int main()
{
int k;
scanf("%d",&k);
while (k--)
{
int n,le,ri,i,length=0,lmin=100000,rmax=-100000;
scanf("%d",&n);
Line L[1000];
for(i=0;i<n;i++)
{
scanf("%d%d",&le,&ri);
if(le>ri)
{
int t=le;
le=ri;
ri=t;
}
if(lmin>le)
{
lmin=le;
}
if(rmax<ri)
{
rmax=ri;
}
L[i].ll=le;
L[i].rr=ri;
}
make(lmin,rmax,1);
qsort(L,n,sizeof(L[0]),cmp);//将个线段以左端点为基准进行增序排序
for(i=0;i<n;i++)
{
cover(L[i].ll,L[i].rr,1);
}
printf("%d\n",count(1));
}
return 0;
}