• BZOJ 1798: [Ahoi2009]Seq 维护序列seq (线段树乘法加法的混合操作)


    

     题目:点击打开链接

    大意:一个数组。三个操作。第一种是区间[a,b]每一个数乘乘,另外一种是区间[a,b]每一个数加c,第三种是查询[a,b]区间的和并对p取摸。

    两种操作就不能简单的仅仅往下传标记。每次传乘法标记时。要把加法标记同一时候乘上乘法标记,比如某个区间先进来一个加法标记add。之后又进来一个乘法标记mul。

    那么结果为(x + add) * mul = x * mul + add * mul。

    这样向下传标记的时候就相对独立。递归边界更新加法标记之前先乘上该节点的mul。左右儿子down的时候先将儿子的add乘上本节点的mul。

    最后说一下sum,比方本节点的存在加法标记x和乘法标记y,而且是先加上x,再乘上y,则左儿子的sum要更新为(sum+x)*y。因为乘法标记传到本节点的时候更新了加法标记,x = x*y,所以sum[o<<1] = (左区间的长度*x) + sum[o<<1]*y。


    /**************************************************************
        Problem: 1798
        User: __ElemenT
        Language: C++
        Result: Accepted
        Time:4676 ms
        Memory:10184 kb
    ****************************************************************/
     
    #include <cstdio>
    #define lson o<<1, l, m
    #define rson o<<1|1, m+1, r
    typedef long long LL;
    const int maxn = 100005;
     
    int n, a, b, c, k, q;
    LL sum[maxn<<2], add[maxn<<2], mul[maxn<<2], p;
     
    void up(int o) {
        sum[o] = (sum[o<<1]+sum[o<<1|1]) %p;
    }
     
    void build(int o, int l, int r) {
        add[o] = 0, mul[o] = 1;
        if(l == r) {
            scanf("%lld", &sum[o]);
            return;
        }
        int m = (l+r) >> 1;
        build(lson);
        build(rson);
        up(o);
    }
     
    void down(int o, int len) {
       // if(add[o] != 0 && mul[o] != 1) {
            add[o<<1] = (add[o<<1] * mul[o] + add[o]) %p;
            add[o<<1|1] = (add[o<<1|1] * mul[o] + add[o]) %p;
            mul[o<<1] = mul[o<<1] * mul[o] %p;
            mul[o<<1|1] = mul[o<<1|1] * mul[o] %p;
            sum[o<<1] = (sum[o<<1] * mul[o] + add[o] * (len-(len>>1))) %p;
            sum[o<<1|1] = (sum[o<<1|1] * mul[o] + add[o] * (len>>1)) %p;
            add[o] = 0, mul[o] = 1;
       // }
    }
     
    void update(int o, int l, int r, int op) {
        if(a <= l && r <= b) {
            if(op == 1) {
                add[o] = add[o]*c %p;
                mul[o] = mul[o]*c %p;
                sum[o] = sum[o]*c %p;
            } else {
                add[o] = (add[o] + c) %p;
                sum[o] = (sum[o] + (LL)c*(r-l+1)) %p;
            }
            return;
        }
        down(o, r-l+1);
        int m = (l+r) >> 1;
        if(a <= m) update(lson, op);
        if(m < b ) update(rson, op);
        up(o);
    }
     
    LL query(int o, int l, int r) {
        if(a <= l && r <= b) return sum[o] %p;
        down(o, r-l+1);
        int m = (l+r) >> 1;
        LL ans = 0;
        if(a <= m) ans = query(lson);
        if(m < b ) ans += query(rson);
        return ans %p;
    }
     
    int main()
    {
        scanf("%d%lld", &n, &p);
        build(1, 1, n);
        scanf("%d", &q);
        while(q--) {
            scanf("%d%d%d", &k, &a, &b);
            if(k != 3) {
                scanf("%d", &c);
                update(1, 1, n, k);
            } else printf("%lld
    ", query(1, 1, n));
        }
        return 0;
    }
    

  • 相关阅读:
    WebUploader IE9下报错
    raphael 支持group(简)
    SVG image xlink:href 设置失败
    活动倒计时代码(精确到毫秒)jquery插件
    PHP连续签到
    PHP判断是否微新浏览器
    php中文匹配
    PHP+mysql统计排名第几位
    php随机抽奖实例分析
    类似a:hover的伪类的注解
  • 原文地址:https://www.cnblogs.com/yutingliuyl/p/6860091.html
Copyright © 2020-2023  润新知