九度OJ 1088:剩下的树 (线段树)

时间限制:1 秒

内存限制:32 兆

特殊判题:

提交:5791

解决:2649

题目描述:

    有一个长度为整数L(1<=L<=10000)的马路,可以想象成数轴上长度为L的一个线段,起点是坐标原点,在每个整数坐标点有一棵树,即在0,1,2,...,L共L+1个位置上有L+1棵树。
    现在要移走一些树,移走的树的区间用一对数字表示,如 100 200表示移走从100到200之间(包括端点)所有的树。
    可能有M(1<=M<=100)个区间,区间之间可能有重叠。现在要求移走所有区间的树之后剩下的树的个数。

输入:

    两个整数L(1<=L<=10000)和M(1<=M<=100)。
    接下来有M组整数,每组有一对数字。

输出:

    可能有多组输入数据,对于每组输入数据,输出一个数,表示移走所有区间的树之后剩下的树的个数。

样例输入:
500 3
100 200
150 300
470 471
样例输出:
298
来源:
2011年清华大学计算机研究生机试真题

思路:

我写代码1的时候还不知道线段树的概念,用了一种比较笨的方法,每次对区间内所有数赋值操作。这个题时间复杂度要求不高,能通过。

后来学了一下线段树,用线段树实现的,见代码2。很奇怪的是线段树的时间复杂度并没有显著改善


代码1:

#include <stdio.h>
#include <string.h>
 
#define N 10000
 
int main(void)
{
    int L, M;
    int moved[N+1];
    int i, j;
    int begin, end;
 
    while (scanf("%d%d", &L, &M) != EOF)
    {
        memset(moved, 0, (N+1)*sizeof(int));
        for (i=0; i<M; i++)
        {
            scanf("%d%d", &begin, &end);
            for (j=begin; j<=end; j++)
                moved[j] = 1;
        }
        int count = 0;
        for (j=0; j<=L; j++)
            count += moved[j];
        printf("%d\n", L+1-count);
    }
 
    return 0;
}
/**************************************************************
    Problem: 1088
    User: liangrx06
    Language: C
    Result: Accepted
    Time:50 ms
    Memory:912 kb
****************************************************************/

代码2:

#include <stdio.h>
#include <limits.h>
 
#define N 10001
 
int seg[4*N];
 
void pushdown(int i)
{
    if (seg[i] != -1)
    {
        seg[2*i] = seg[i];
        seg[2*i+1] = seg[i];
        seg[i] = -1;
    }
}
 
void update(int k, int i, int b, int e, int l, int r)
{
    if (b > r || e < l)
        return;
    if (l <= b && e <= r)
    {
        seg[i] = k;
        return;
    }
    pushdown(i);
    update(k, 2*i, b, (b+e)/2, l, r);
    update(k, 2*i+1, (b+e)/2+1, e, l, r);
}
 
int getsum(int i, int b, int e)
{
    if (seg[i] == -1)
        return getsum(2*i, b, (b+e)/2) + getsum(2*i+1, (b+e)/2+1, e);
    if (seg[i] == 1)
        return e-b+1;
    else
        return 0;
}
 
int main(void)
{
    int n, i, m;
    int l, r;
 
    while (scanf("%d%d", &n, &m) != EOF)
    {
        for (i=0; i<4*N; i++)
            seg[i] = -1;
        update(1, 1, 0, n, 0, n);
 
        for (i=0; i<m; i++)
        {
            scanf("%d%d", &l, &r);
            update(0, 1, 0, n, l, r);
        }
        printf("%d\n", getsum(1, 0, n));
    }
 
    return 0;
}
/**************************************************************
    Problem: 1088
    User: liangrx06
    Language: C
    Result: Accepted
    Time:40 ms
    Memory:1068 kb
****************************************************************/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值