洛谷 P3373 【模板】线段树 2

P3373 【模板】线段树 2

题目描述

如题,已知一个数列,你需要进行下面三种操作:

1.将某区间每一个数乘上x

2.将某区间每一个数加上x

3.求出某区间每一个数的和

输入

第一行包含三个整数N、M、P,分别表示该数列数字的个数、操作的总个数和模数。

第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。

接下来M行每行包含3或4个整数,表示一个操作,具体如下:

操作1: 格式:1 x y k 含义:将区间[x,y]内每个数乘上k

操作2: 格式:2 x y k 含义:将区间[x,y]内每个数加上k

操作3: 格式:3 x y 含义:输出区间[x,y]内每个数的和对P取模所得的结果

输出

输出包含若干行整数,即为所有操作3的结果。

样例

输入样例#1: 复制
5 5 38
1 5 4 2 3
2 1 4 1
3 2 5
1 2 4 2
2 3 5 5
3 1 4
输出样例#1: 复制
17
2
时空限制:1000ms,128M

数据规模:

对于30%的数据:N<=8,M<=10

对于70%的数据:N<=1000,M<=10000

对于100%的数据:N<=100000,M<=100000

题意

改了好长时间的pushdown函数 运算优先级加法优先TAT

AC代码

#include <bits/stdc++.h>
using namespace std;

#define LL long long
#define CLR(a,b) memset(a,(b),sizeof(a))
#define ls  st<<1
#define rs st<<1|1
const LL MAXN = 1e6+10;
LL a[MAXN];
LL n, m, p;
struct node
{
    LL l, r;
    LL len;
    LL val, mul, add;
}tree[MAXN];

void build(LL l, LL r, LL st)
{
    tree[st].l = l, tree[st].r = r;
    tree[st].mul = 1, tree[st].add = 0;
    tree[st].len = r-l+1;
    if(l == r) {
        tree[st].val = a[l];
        return ;
    }
    else {
        LL mid = (l+r)>>1;
        build(l,mid,ls);
        build(mid+1,r,rs);
        tree[st].val = tree[ls].val+tree[rs].val;
    }
    tree[st].val %= p;
    return ;
}
void push_down(LL st)
{
//    if(tree[st].mul!=1) {
//        tree[ls].mul = (tree[st].mul*tree[ls].mul)%p;
//        tree[rs].mul = (tree[st].mul*tree[rs].mul)%p;
//        tree[ls].val = (tree[st].mul*tree[ls].val+tree[st].add*tree[ls].len)%p;
//        tree[rs].val = (tree[st].mul*tree[rs].val+tree[st].add*tree[rs].len)%p;
//        tree[st].mul = 1;
//    }
//    if(tree[st].add) {
//        tree[ls].add = (tree[ls].add*tree[st].mul+tree[st].add)%p;
//        tree[rs].add = (tree[rs].add*tree[st].mul+tree[st].add)%p;
//        tree[ls].val = (tree[st].mul*tree[ls].val+tree[st].add*tree[ls].len)%p;
//        tree[rs].val = (tree[st].mul*tree[rs].val+tree[st].add*tree[rs].len)%p;
//        tree[st].add = 0; //tree[st].mul = 1;
//    }
        tree[rs].add = (tree[rs].add*tree[st].mul+tree[st].add)%p;
        tree[ls].add = (tree[ls].add*tree[st].mul+tree[st].add)%p;
        tree[ls].mul = (tree[st].mul*tree[ls].mul)%p;
        tree[rs].mul = (tree[st].mul*tree[rs].mul)%p;
        tree[ls].val = (tree[st].mul*tree[ls].val+tree[st].add*tree[ls].len)%p;
        tree[rs].val = (tree[st].mul*tree[rs].val+tree[st].add*tree[rs].len)%p;
        tree[st].add = 0;
        tree[st].mul = 1;
}
void update_1(LL l, LL r,LL st, LL k)
{
    if(l<=tree[st].l && r>=tree[st].r) {
        tree[st].val = (tree[st].val*k)%p;
        tree[st].mul = (tree[st].mul*k)%p;
        tree[st].add = (tree[st].add*k)%p;
        return ;
    }
    if(l>tree[st].r || r<tree[st].l)
        return ;
    push_down(st);
    update_1(l,r,ls,k);
    update_1(l,r,rs,k);
    tree[st].val = (tree[ls].val+tree[rs].val)%p;
    return ;
}
void update_2(LL l, LL r, LL st, LL k)
{
    if(l<=tree[st].l && r>=tree[st].r) {
        tree[st].val = (tree[st].val+k*(tree[st].len))%p;
        tree[st].add = (tree[st].add+k)%p;
        return ;
    }
    if(l>tree[st].r || r<tree[st].l)
        return ;
    push_down(st);
    update_2(l,r,ls,k);
    update_2(l,r,rs,k);
    tree[st].val = (tree[ls].val+tree[rs].val)%p;
    return ;
}
LL query(LL l, LL r, LL st)
{
    if(l<=tree[st].l && r >= tree[st].r)
        return tree[st].val;
    if(l>tree[st].r || r<tree[st].l)
        return 0;
    push_down(st);
    return (query(l,r,ls)+query(l,r,rs))%p;
}
int main()
{
    ios::sync_with_stdio(false);
    cin >> n >> m >> p;
    for(LL i = 1; i <= n; i++)
        cin >> a[i];
    build(1,n,1);
    while(m--) {
        LL q;
        LL x, y, k;
        cin >> q;
        if(q == 1) {
            cin >> x >> y >> k;
            update_1(x,y,1,k);
        }
        if(q == 2) {
            cin >> x >> y >> k;
            update_2(x,y,1,k);
        }
        if(q == 3) {
            cin >> x >> y;
            cout << query(x,y,1) << endl;
        }
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值