Color the ball (线段树,区间更新模板题)

其实是很简单的一道题,由于一开始不会线段树的区间更新所以一直WA,网上题解大部分都是树状数组搞得,道不同啊,所以一直自己死扣,终于A了,真心不容易;

好了,先说说线段树的区间更新,这是点更新的扩展,点更新很简单,当然你可以用个循环加点更新,不过,效率太慢,如果有上千条上万条操作肯定T了,所以伟大的码农们想到了一个方法,懒惰标记,简单来说就是更新的时候你用到那一层就更新到那一层,用不到的就标记下来,等下次用到了再更新,同时消除标记;

看到这肯定迷糊了,还是来道题学习一下吧;

     N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的“小飞鸽"牌电动车从气球a开始到气球b依次给每个气球涂一次颜色。但是N次以后lele已经忘记了第I个气球已经涂过几次颜色了,你能帮他算出每个气球被涂过几次颜色吗?
Input
    每个测试实例第一行为一个整数N,(N <= 100000).接下来的N行,每行包括2个整数a b(1 <= a <= b <= N)。
    当N = 0,输入结束。
Output
    每个测试实例输出一行,包括N个整数,第I个数代表第I个气球总共被涂色的次数。
Sample Input

    3
    1 1
    2 2
    3 3
    3
    1 1
    1 2
    1 3
    0

Sample Output

    1 1 1
    3 2 1

很简单的题吧,粉刷气球,每次操作把相应区间内的气球粉刷一遍,问最后每个气球分别被粉刷了多少遍;

来看看代码;

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#define MAX 100000+5
using namespace std;
int segtree[MAX<<2];              //树结点,用来储存气球的粉刷次数,由于此题只与叶结点有关,所以中间节点的值不需要关心;
int lazy[MAX<<2];                 //懒惰标记;
int N;                            //气球个数;
void build(int node, int left, int right){//建立线段树,叶结点全部为零;
    if(left==right){
        segtree[node]=0;
        return;
    }
    int mid=(left+right)>>1;
    build(node<<1, left, mid);
    build(node<<1|1, mid+1, right);
}
void pushdown(int node, int left, int right){//如果该层被标记,那么对他的左右孩子更新;
    if(left!=right){//这句判断一定要加,不然会RE,血淋淋得教训啊;
    segtree[node<<1]+=lazy[node];//更新左孩子;
    segtree[node<<1|1]+=lazy[node];//更新右孩子;
    lazy[node<<1|1]+=lazy[node]; //把标记传入下一层;
    lazy[node<<1]+=lazy[node];
    }
    lazy[node]=0;        //消除标记;
}
void update(int node, int left, int right, int l, int r, int add){//区间更新;传参:树根,区间范围,需要更新的区间,每个数要增加的值;
    if(lazy[node]) pushdown(node, left, right);//先判断该层是否被标记,如果被标记就更新一次;
    if(l>right || r<left) return;
    if(l<=left && r>=right){
        lazy[node]+=add;                       //找到更新区间后标记该层,表示该层以下需要被更新,需要增加的值为lazy内的值;
        segtree[node]+=lazy[node];             //更新该层;
        return;
    }
    int mid=(left+right)>>1;
    update(node<<1, left, mid, l, r, add);
    update(node<<1|1, mid+1, right, l, r, add);
}
void query(int node, int left, int right){
    if(lazy[node]) pushdown(node, left, right);//不管查询还是更新每次都要先判断该层是否被更新;
    if(left==right){         //if左右孩子相等,该点是叶结点,输出叶结点;
        if(left==N) printf("%d\n",segtree[node]);
        else printf("%d ",segtree[node]);
        return;
    }
    int mid=(left+right)>>1;
    query(node<<1, left, mid);
    query(node<<1|1, mid+1, right);
}
int main(){
    while(scanf("%d",&N),N!=0){
        int a, b;
        int i;
        build(1, 1, N);
        memset(lazy, 0, sizeof(lazy));
        for(i=1; i<=N; i++){
            scanf("%d%d",&a,&b);
            update(1, 1, N, a, b, 1);
        }
    query(1, 1, N);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值