NOIP2005普及组T2(线段树解法)

先上题面

题目描述

某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是 11 米。我们可以把马路看成一个数轴,马路的一端在数轴 00 的位置,另一端在 LL 的位置;数轴上的每个整数点,即 0,1,2,…,L0,1,2,,L ,都种有一棵树。

由于马路上有一些区域要用来建地铁。这些区域用它们在数轴上的起始点和终止点表示。已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分。现在要把这些区域中的树(包括区域端点处的两棵树)移走。你的任务是计算将这些树都移走后,马路上还有多少棵树。

输入输出格式

输入格式:

第一行有 22 个整数 L(1 \le L \le 10000)L(1L10000) 和 M(1 \le M \le 100)M(1M100) , LL 代表马路的长度, MM 代表区域的数目, LL和 MM 之间用一个空格隔开。
接下来的 MM 行每行包含 22 个不同的整数,用一个空格隔开,表示一个区域的起始点和终止点的坐标。

输出格式:

1

1 个整数,表示马路上剩余的树的数目。


很容易看出,这道题哪怕是用纯模拟也不会爆(毕竟是2005年的原题)

但今天水货笔者不是来写模拟算法的,是来写线段树解法的(不知道线段树的小同学们可以上网搜一下再继续往下)


一言不合附上程序:
#include
using namespace std;
int read(){
    char c=getchar();
    int num=0;int f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){num=num*10+(c-'0');c=getchar();}
    return num*f;
}
void qwq(int x){
    if(x>9)qwq(x/10);
    putchar(x%10+'0');
}
void write(int x){
    if(x<0){x=-x;putchar('-');}
    qwq(x);putchar('\n');
}//丑陋的读入/输出优化
struct wzy{
    int l,r,value;//value表示树们是否已被全部移走
    int be;//be表示是否一个有效的子节点
}tree[400010];
void build(int ll,int rr,int number){
    if(ll>rr)return;
    tree[number].l=ll;tree[number].r=rr;tree[number].be=1;
    if(ll==rr)return;
    int mid=(ll+rr)/2;
    build(ll,mid,number*2);
    build(mid+1,rr,number*2+1);
}//建树过程......没啥好说的......
void in(int number,int il,int ir){
    if(il<=tree[number].l&&tree[number].r<=ir){
        tree[number].value=1;
        return;
    }else{
        if(il<=(tree[number].l+tree[number].r)/2){
            in(number*2,il,ir);
        }
        if(ir>(tree[number].l+tree[number].r)/2){
            in(number*2+1,il,ir);
        }
        if(tree[number*2].value&&tree[number*2+1].value)tree[number].value=1;//若两个子节点所表示的树们均被移走,那父节点本身也是如此。
    }
}
int ans=0;//这里表示被移走的总数量
void found(int number){
    if(!tree[number].be)return;//不是有效的子节点,返回。
    if(tree[number].value==1){//找到一个树们已被全部移走的区间
        ans+=tree[number].r-tree[number].l+1;
        return;
    }else{
        found(number*2);found(number*2+1);	
    }
}
int main(){
    int n=read();int m=read();
    build(0,n,1);
    for(int i=1;i<=m;i++){
        int x=read();int y=read();
        in(1,x,y);
    }
    found(1);write(n+1-ans);//0到n共有(n+1)棵树,所以剩余的树们的数量就是(n+1-ans)。
    return 0;
}

你可能感兴趣的:(线段树)