zoukankan      html  css  js  c++  java
  • 线段树

    首先先说明本题的思路。题目要求有三种操作,两种是不同的在线修改,还有一种是在查询取模后的结果。而这两种操作又是区间乘法和区间加法,我们可以惊喜的发现这两种操作对于取模运算来说都是自由的!但是面对非常大的数据,我们必须思考怎么样用线段树优雅的跑过这道题目。

    面对这两种操作,可以联想到线段树的一个非常好的功能就是lazytag,只计算出确实需要访问的区间的真实值,其他的保存在lazytag里面,这样可以近似O(NlogN)的运行起来。在尝试着写了只有一个lazetag的程序之后我们发现一个lazytag是不能够解决问题的,那就上两个,分别表示乘法意义上的lazytag和加法意义上的lazytag。紧接着想到pushdown操作之后我们又发现必须在向下传递lazytag的时候人为地为这两个lazytag规定一个先后顺序,排列组合一下只有两种情况:

    ①加法优先,即规定好segtree[root*2].value=((segtree[root*2].value+segtree[root].add)*segtree[root].mul)%p,问题是这样的话非常不容易进行更新操作,假如改变一下add的数值,mul也要联动变成奇奇怪怪的分数小数损失精度,我们内心是很拒绝的;

    ②乘法优先,即规定好segtree[root*2].value=(segtree[root*2].value*segtree[root].mul+segtree[root].add*(本区间长度))%p,这样的话假如改变add的数值就只改变add,改变mul的时候把add也对应的乘一下就可以了,没有精度损失,看起来很不错。

    inline void build (LL l,LL r,LL rt) {//建树
        if (l == r) { sum [rt] = a[l] ; return ; }
        LL mid = l + r >> 1;
        build ( l , mid , rt<<1 ) ;
        build ( mid+1 ,r, rt << 1|1 ) ;
        sum [rt] = sum [rt<<1] + sum [rt<<1|1] ;
        sum [rt] %= p ; mul [rt] = 1;
    }
    //核心代码,维护线段树
    inline void push_down (LL l,LL r,LL rt){
        int mid = l + r >> 1 ;
        add [ rt<<1 ] = (add [rt<<1] * mul [rt] + add [rt] ) % p ;
        add [ rt<<1|1 ] = (add [rt<<1|1] * mul [rt] + add [rt] ) % p ;
        mul [ rt<<1 ] = (mul [rt<<1] * mul [rt] ) % p ;
        mul [ rt<<1|1 ] = (mul [rt<<1|1] * mul [rt] ) % p ;
        sum [ rt<<1 ] = (sum [rt<<1] * mul [rt] + add [rt] * ( mid - l + 1 ) ) %p ;
        sum [ rt<<1|1 ] = (sum [rt<<1|1] * mul [rt] + add [rt] * (r-mid) ) %p ;
        add [ rt ] = 0 ; mul [rt] = 1 ;
    }
    //乘法
    inline void longer_write_add (LL a,LL b,LL l,LL r,LL rt,LL j){
        if (a<=l and r<=b){
            sum[rt] += j*(r-l+1) ; add[rt] += j ; return ;
        }
        push_down(l, r, rt) ;
        LL mid= l + r >> 1;
        if ( a <= mid ) longer_write_add(a, b, l, mid, rt<<1, j) ;
        if ( b > mid ) longer_write_add(a, b, mid+1, r, rt<<1|1, j) ;
        sum [ rt ] = sum [ rt<<1 ] + sum [ rt<<1|1 ] ;
        sum [ rt ] %= p ;
    }
    //同上 加法
    inline LL longer_query (LL L,LL R,LL l,LL r,LL rt){
        if ( L <= l and r <= R ){ return sum[rt] ;}
        push_down(l, r, rt) ;
        LL mid = l + r >> 1 ;
        LL ans1 , ans2 ; ans1 = ans2 = 0 ;
        if(L<=mid) ans1=longer_query(L, R, l, mid, rt<<1);
        if(mid<R) ans2=longer_query(L, R, mid+1, r, rt<<1|1);
        return ( ans1 + ans2 ) % p ;
    }

    code

     

    不存在十全十美的文章 如同不存在彻头彻尾的绝望
  • 相关阅读:
    Ubuntu Server中怎样卸载keepalived
    Winform中实现ZedGraph滚轮缩放后自动重新加载数据
    Winform中自定义添加ZedGraph右键实现设置所有Y轴刻度的上下限
    C#中获取多个对象list中对象共有的属性项
    Windows7中启动Mysql服务时提示:拒绝访问的一种解决方式
    八、子查询实践
    四、bootstrap-Table
    二、sql新增后返回主键|sql 使用 FOR XML PATH实现字符串拼接|sql如果存在就修改不存在就新增
    一、动词、名词、形容词汇位置
    三、TortoiseSVN 单独拉取项目某个文件
  • 原文地址:https://www.cnblogs.com/qf-breeze/p/10467102.html
Copyright © 2011-2022 走看看