解题思路:


这个题解是我从博客上摘抄下来的 
和大家一起分享
这个题目用到了线段树的知识  因为用普通的循环  我们得到的时间复杂度为O(m*n) 肯定会超时
 
这个题目比较复杂 我写的也不是很好  大家多看几遍  多理解 
个人水平 有限  欢迎批评指正~


所谓的线段树如下图:

每个数的结点 里面包含的是线段  

比如根结点包含的线段范围为[a,b]

那么它的左子结点 包含线段的范围为[a,(a+b)/2]   右子结点包含的线段范围为[(a+b)/2+1,b]

(a+b)/2即为mid,如此这样一直分支下去 直到每个结点中包含的线段成了一个点  线段树便构建好了

QQ截图20171215151025.png
参考代码:

#include <iostream>  
#include <string.h>  
#include <algorithm>  
#include <cstdio>  
#include <math.h>  
using namespace std;  
const int N=100000+10;  
struct Node{  
    int l,r,v;  
}node[N*4]; //线段树的每个节点  其中包括三个参数 l为线段左端点的值 r:线段右端点的值  v:该节点所存储的值 
void Init(int now,int le,int ri){    //构建线段树 并将结点的值初始化全部为0   
      if(le==ri){  
        node[now].l=le;  
        node[now].r=ri;  
        node[now].v=0;  
        return;  
      }//如果线段的左端点==线段的右端点  那么即是最后的叶子结点 return  
      int mid=(le+ri)>>1;  //求出中点
      int ne=now<<1;    //将结点的序号*2;
      Init(ne,le,mid);  //构建左子树
      Init(ne+1,mid+1,ri);  //构建右子树
      node[now].l=le;  //给当前结点的线段左右端点赋值
      node[now].r=ri;  
      node[now].v=0;  //给结点赋值
}  
void insert(int now,int le,int ri,int add){       //在线段树中寻找对应的区间  给对应该区间的结点加上该发的
苹果数,即为在那个结点下的所有的子节点的区间里的小孩均会被发苹果。 (pinrt函数中会提到)
    if(node[now].l==le&&node[now].r==ri){  
        node[now].v+=add;  
        return;  
    }  //给对应该区间的结点加上发的苹果数
    int mid=(node[now].l+node[now].r)>>1;//求出中点  
    int ne=now<<1;  //结点的序号*2,方便构建新的结点
     if(ri<=mid){  
        insert(ne,le,ri,add);  //如果寻找的区间的右端点小于中点 则在左边寻找
     }      
    else if(le>mid){  
         insert(ne+1,le,ri,add);  //反之在右边寻找
    }          
    else  
    {  
        insert(ne,le,mid,add);  //如果横跨两边  左右两边都寻找
        insert(ne+1,mid+1,ri,add);  
    }  
}   
void print(int now){  
    if(node[now].l==node[now].r){  
        cout<<node[now].v<<" ";  
        return;  
        }   //如果是最后的叶子结点 输出小朋友的苹果总数
    int ne=now<<1;  
    //父亲的范围大 包含的儿子结点的区间   所以父亲下面儿子结点也要加上父亲结点被发的苹果数  
    node[ne].v+=node[now].v;  
    print(ne);  
    node[ne+1].v+=node[now].v;  
    print(ne+1);  
}  
int main(){  
    int n,m,i,a,b,c;  
    while(cin>>n>>m){  
        Init(1,1,n);  
        for(i=0;i<m;i++){  
            cin>>a>>b>>c;  
            insert(1,a,b,c);  
        }  
        print(1);  
    }  
    return 0;  
}


点赞(11)
 

0.0分

5 人评分

C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:

一点编程也不会写的:零基础C语言学练课程

解决困扰你多年的C语言疑难杂症特性的C语言进阶课程

从零到写出一个爬虫的Python编程课程

只会语法写不出代码?手把手带你写100个编程真题的编程百练课程

信息学奥赛或C++选手的 必学C++课程

蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程

手把手讲解近五年真题的蓝桥杯辅导课程

评论列表 共有 12 条评论

叶奇 2年前 回复TA
线段树优化,真离谱
陈晨晨 4年前 回复TA
棒棒哒!!
陈晨晨 4年前 回复TA
棒棒哒!!
陈晨晨 4年前 回复TA
棒棒哒!!
陈晨晨 4年前 回复TA
棒棒哒!!
陈晨晨 4年前 回复TA
棒棒哒!!
陈晨晨 4年前 回复TA
棒棒哒!!
陈晨晨 4年前 回复TA
棒棒哒!!
陈晨晨 4年前 回复TA
棒棒哒!!
陈晨晨 4年前 回复TA
棒棒哒!!