acwing 维护序列 线段树 懒标记(乘和加的序列维护)

老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。

有长为 N 的数列,不妨设为 a1,a2,…,aN。

有如下三种操作形式:

把数列中的一段数全部乘一个值;
把数列中的一段数全部加一个值;
询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模 P 的值。
输入格式
第一行两个整数 N 和 P;

第二行含有 N 个非负整数,从左到右依次为 a1,a2,…,aN;

第三行有一个整数 M,表示操作总数;

从第四行开始每行描述一个操作,输入的操作有以下三种形式:

操作 1:1 t g c,表示把所有满足 t≤i≤g 的 ai 改为 ai×c;
操作 2:2 t g c,表示把所有满足 t≤i≤g 的 ai 改为 ai+c;
操作 3:3 t g,询问所有满足 t≤i≤g 的 ai 的和模 P 的值。
同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。

输出格式
对每个操作 3,按照它在输入中出现的顺序,依次输出一行一个整数表示询问结果。

数据范围
1≤N,M≤105,
1≤t≤g≤N,
0≤c,ai≤109,
1≤P≤109
输入样例:
7 43
1 2 3 4 5 6 7
5
1 2 5 5
3 2 4
2 3 7 9
3 1 3
3 4 7
输出样例:
2
35
8
样例解释
初始时数列为 {1,2,3,4,5,6,7};

经过第 1 次操作后,数列为 {1,10,15,20,25,6,7};

对第 2 次操作,和为 10+15+20=45,模 43 的结果是 2;

经过第 3 次操作后,数列为 {1,10,24,29,34,15,16};

对第 4 次操作,和为 1+10+24=35,模 43 的结果是 35;

对第 5 次操作,和为 29+34+15+16=94,模 43 的结果是 8。

#include<bits/stdc++.h>
using namespace std;
const   int N=100010;
int n,p;
int m;
typedef long long ll;
struct node{
    int l;
    int r;
    ll sum;
    int mul,add;
}tr[N*4];
int w[N];
void pushup(int u)
{
    tr[u].sum=(tr[u<<1|1].sum+tr[u<<1].sum)%p;
}
void eva(int u,int fa)
{

    tr[u].sum=((ll)tr[u].sum*tr[fa].mul+(ll)tr[fa].add*(tr[u].r-tr[u].l+1))%p;
         tr[u].mul=((ll)tr[u].mul*tr[fa].mul)%p;
    tr[u].add=((ll)tr[u].add*tr[fa].mul+tr[fa].add)%p;

}
void pushdown(int u)
{
    eva(u<<1,u);
    eva(u<<1|1,u);
    tr[u].mul=1;
    tr[u].add=0;
    return ;
}
void build(int u,int l,int r)
{
    tr[u]={l,r,0,1,0};
    if(l==r)
    {
        tr[u].sum=w[r];
    }
    else
    {
        int mid=l+r>>1;
        build(u<<1,l,mid),build(u<<1|1,mid+1,r);
        pushup(u);
    }
}
void modify(int u,int l,int r,int mul,int add)
{
    if(tr[u].l>=l&&tr[u].r<=r)
    {
        tr[u].sum=((ll)tr[u].sum*mul+(ll)add*(tr[u].r-tr[u].l+1))%p;
        tr[u].mul=((ll)tr[u].mul*mul)%p;
        tr[u].add=((ll)add+(ll)tr[u].add*mul)%p;
        return ;
    }
    else
    {
        pushdown(u);
        int mid=tr[u].l+tr[u].r>>1;
        if(l<=mid)  modify(u<<1,l,r,mul,add);
        if(r>mid)   modify(u<<1|1,l,r,mul,add);
        pushup(u);
    }
}
int query(int u,int l,int r)
{
    if(tr[u].l>=l&&tr[u].r<=r)
    return tr[u].sum;
    pushdown(u);
    int mid=tr[u].l+tr[u].r>>1;
    ll ans=0;
    if(l<=mid)  ans= query(u<<1,l,r);
    if(r>mid)   ans+= query(u<<1|1,l,r);
    return ans%p;
}
int main()
{
    cin>>n>>p;
    for(int i=1;i<=n;i++)
    cin>>w[i];
    build(1,1,n);
    cin>>m;
    while(m--)
    {
        int op;
        cin>>op;
        if(op==1)
        {
            int l,r,d;
            cin>>l>>r>>d;
            modify(1,l,r,d,0);
        }
        else if(op==2)
        {
            int l,r,d;
            cin>>l>>r>>d;
            modify(1,l,r,1,d);
        }
        else
        {
            int l,r;
            cin>>l>>r;
            cout<<query(1,l,r)<<endl;
        }
    }
    return 0;
}
全部评论

相关推荐

不愿透露姓名的神秘牛友
11-29 12:19
点赞 评论 收藏
分享
10-11 17:45
门头沟学院 Java
走吗:别怕 我以前也是这么认为 虽然一面就挂 但是颇有收获!
点赞 评论 收藏
分享
10-14 10:56
已编辑
长沙学院 嵌入式软件开发
痴心的00后拿到了ssp:hr面挂了,无所谓了反正不去😃
点赞 评论 收藏
分享
11-30 11:07
河南大学 Java
宇宙厂 测开 n*15
丘丘给个offer:有后选后
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务