线段覆盖长度

问题描述:给定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                                                               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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值