洛谷P2023 && bzoj1798 [AHOI2009]维护序列

线段树裸题不解释,注意取膜和乘法标记对加法标记的影响就好了

#include <bits/stdc++.h>
#define Ls(x) x << 1
#define Rs(x) x << 1 | 1
using namespace std;
int n, m;
long long mod;
const int maxn = 100000 + 10;
long long a[maxn];
template<class T>void read(T &x)
{
    x = 0;int f = 0;int ch = getchar();
    while(ch < '0' || ch > '9')  {f |= (ch == '-'); ch = getchar();}
    while(ch >=  '0'&&ch <= '9'){x = x * 10+(ch^48); ch = getchar();}
    x = f?-x:x;
    return;
}
struct SegmentTree{
    int l, r, len;
    long long tag;
    long long mult;
    long long val;
    SegmentTree()
    {
        tag = 0;val = 0;mult = 1;
        l = r = len = 0;
    }
}tre[maxn << 2];
void build(int rt, int l, int r)
{
    tre[rt].l = l, tre[rt].r = r, tre[rt].len = r - l + 1;
    if(l == r) {
        tre[rt].val = a[l];
        return ;
    }
    int mid = (l + r) >> 1;
    build(Ls(rt), l, mid);
    build(Rs(rt), mid + 1, r);
    tre[rt].val = (tre[Ls(rt)].val + tre[Rs(rt)].val) % mod;
}
void push_down(int rt) {
    tre[Ls(rt)].mult =  tre[Ls(rt)].mult * tre[rt].mult % mod;
    tre[Ls(rt)].tag = (tre[Ls(rt)].tag * tre[rt].mult + tre[rt].tag) % mod;
    tre[Ls(rt)].val  = (tre[Ls(rt)].val  * tre[rt].mult + tre[rt].tag * (tre[Ls(rt)].len)) % mod;
    tre[Rs(rt)].mult =  tre[Rs(rt)].mult * tre[rt].mult % mod;
    tre[Rs(rt)].tag = (tre[Rs(rt)].tag * tre[rt].mult + tre[rt].tag) % mod;
    tre[Rs(rt)].val  = (tre[Rs(rt)].val  * tre[rt].mult + tre[rt].tag * (tre[Rs(rt)].len)) % mod;
    tre[rt].mult=1;tre[rt].tag=0;
}
void update(int rt, int L, int R, long long delta, int k) {
    int l = tre[rt].l, r = tre[rt].r;
    int mid = (l + r) >> 1;
    if(l >= L && r <= R) {
        if(k == 2) {
            tre[rt].tag = (tre[rt].tag + delta) % mod;
            tre[rt].val = (tre[rt].val + delta * tre[rt].len) % mod;
        }
        else {
            tre[rt].mult = tre[rt].mult * delta % mod;
            tre[rt].tag = tre[rt].tag * delta % mod;
            tre[rt].val = tre[rt].val * delta % mod;
        }
        return ;
    }
    if(tre[rt].mult != 1 || tre[rt].tag ) push_down(rt);
    if(L <= mid) update(Ls(rt), L, R, delta, k);
    if(R > mid)  update(Rs(rt), L, R, delta, k);
    tre[rt].val = (tre[Ls(rt)].val + tre[Rs(rt)].val) % mod;
    return ;
}
long long query(int rt, int L, int R) {
    int l = tre[rt].l, r = tre[rt].r;int mid = (l + r) >> 1;
    if(l >= L && r <= R) {
    	return tre[rt].val;
    }
    if(tre[rt].mult != 1 || tre[rt].tag ) push_down(rt);
    long long res = 0;
    if(L <= mid) res += query(Ls(rt), L, R);
    if(mid < R) res += query(Rs(rt), L, R);
    return res % mod;
    
}

signed main()
{
    read(n); read(mod);
    for(int i = 1; i <= n; i++) read(a[i]);
    read(m);
    build(1, 1, n);
    for(int i = 1, opt, l, r; i <= m; i++) {
        read(opt); read(l); read(r);
        long long dif;
        if(opt == 3) {
            printf("%lld\n", query(1, l, r));
        }
        else {
            read(dif);
            update(1, l ,r, dif, opt);
        }
    }
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值