线段树中的离散化与lazy标记思想

线段树研究了三天了!!!第一天理解了线段树是如何操作数据的,但是不太理解线段树的离散化,不知道离散化是用来干嘛的。第二天又研究了好久离散化,才知道其核心!……

其实离散化还是挺容易理解的,比如求一些线段的重合,给出一些线段,如:(2,4),(4,8),(6,8);如果没离散化就建树的话,最大的数是8,那么树就为build(1,8),即最大的上限为8。如果离散化,把这几个数排下序:2,4,6,8;那么分别让2指向1,4指向2,6指向3,8指向4,即1代表2,2代表4,3代表6,4代表8,然后树就为build(1,4),即最大的上限为4,比未离散化之前省了4个量级,树比之前的树就少了很久节点了,即可以省内存,又把时间给节约了,这就是压缩法,即离散化。

刚开始我离散化之前没有排序,然后结果出错,搞了好久才知道要排序,晕……离散化之后求就比较方便了。因为如果ACM题目出的上限为10^9,那么不离散化之前,你肯定要建的树为build(1,10^9),离散化之后看情况建的树,这样就比较好了。比如下面的离散化方法:

	map<int,int>q;
        int p[M],w[M],j=0,n,m,i,c[M],d[M];
        scanf("%d%d",&n,&m);
        for(i=0;i<n;i++)
        {
            scanf("%d%d",&c[i],&d[i]);
            w[j++]=c[i];
            w[j++]=d[i];
        }
        for(i=0;i<m;i++)
        {
            scanf("%d",&p[i]);
            w[j++]=p[i];
        }
        
        sort(w,w+j);   //先排序,因为去重的时候用得到
        int ans=unique(w,w+j)-w;  //unique为C++自带的去重函数,ans为去重后的数组的下标上限
        build(1,1,ans);
        for(i=0;i<ans;i++)
            q[w[i]]=i+1;
        for(i=0;i<n;i++)
            update(1,q[c[i]],q[d[i]]);

lazy思想:我理解和会用离散化之后,又遇到问题了,因为我提交代码的时候TLE了,后面看了别人的代码进行比较,看到别人有:tree[i].lazy,不知道这个是干嘛用的,百度了一下,才知道是用来标记的。就是如果我输入线段(4,8),那么没标记之前,对(4,8)以下的所有左儿子和右儿子都直接加上重复的值了,就是更新树的时候,这条线段以下的所有结点都要更新,而在实际中,这条线段以下的结点可能不会用得到,那么更新这些结点是没有用的,所以在建树的时候顺便加上一个tree[i].lazy,在这条线段的这个结点那,标记这个结点以下要更新的值,即加上或者乘上的值,即tree[i].lazy=value,然后在需要这个结点以下的时候再计算以下的结点就得了,如果不需要,那当然不用计算下面的了。

这个代码就不用给了,百度上好多代码,忘的时候再看别人的吧!

终于把线段树的每个知道点都学会了,现在运用去咯!!!刷几道题巩固一下…………

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值