线段树练习1

题目大意:

桌子上零散地放着若干个盒子,桌子的后方是一堵墙。如右图所示。现在从桌子的前方射来一束平行光, 把盒子的影子投射到了墙上。问影子的总宽度是多少?
数据范围:
l表示墙的长度 1<=l<=100000
n表示盒子数量 1<=n<=100000
数据保证盒子的坐标

解题思路:

线段树
用cover记录该区间的状态,1表示被完全覆盖,0表示没有被完全覆盖。

源程序:

#include<cstdio>
using namespace std;
struct node{
    int x,y;
    bool cover;
}a[1000011];
int l,n,x1,y1;
void insert(int p,int b,int e)//插入算法
{
    if (!a[p].cover)
    //如果当前区间被完全覆盖,再插入盒子就已经没有任何意义
    {
        int mid=(a[p].x+a[p].y)/2;
        if (a[p].x==b&&a[p].y==e)
         a[p].cover=1;
        //如果要插入盒子的区间就是当前区间,则这个区间被完全覆盖
        //否则有三种情况
        else if (e<=mid) insert(p*2,b,e);
        //1.要插入盒子的区间在左孩子的区间范围内,则搜左孩子
        else if (b>=mid) insert(p*2+1,b,e);
        //2.要插入盒子的区间在右孩子的区间范围内,则搜右孩子
        else {
                insert(p*2,b,mid);
                insert(p*2+1,mid,e);
                //3.一部分在左孩子,一部分在右孩子,则两边都搜
                //以中间值为分界线
             }
    }
}
int count_answer(int p)//统计答案
{
    if (a[p].cover) return a[p].y-a[p].x;
    else if (a[p].y-a[p].x==1) return 0;
    else return count_answer(p*2)+count_answer(p*2+1);
    //如果被完全覆盖,则返回整个盒子的长度
    //如果它们表示的区间范围是1,又没有盒子,则退出(防止死循环然后爆掉)
    //不然接着往下搜
}
void build(int i)//建树
{
    if(a[i].y-a[i].x>1)
    //如果它们表示的区间已经是1
    //则说明不能继续分,就要退出循环,不然会爆掉
    {
        int mid=(a[i].x+a[i].y)/2;
        a[i*2].x=a[i].x;
        a[i*2+1].x=mid;
        a[i*2].y=mid;
        a[i*2+1].y=a[i].y;
        build(i*2);
        build(i*2+1);
    }
}
int main()
{
    scanf("%d",&l);
    a[1].x=1;a[1].y=l;
    build(1);
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
     {
        scanf("%d%d",&x1,&y1);
        insert(1,x1,y1);
        //每读入一个盒子,就要插入
     }
    printf("%d",count_answer(1));//统计,愉快地输出
    return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值