ACWING1277. 维护序列

维护序列

原题链接

描述

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

有长为 N 的数列,不妨设为 \(a_1,a_2,…,a_N\)

有如下三种操作形式:

1、把数列中的一段数全部乘一个值;
2、把数列中的一段数全部加一个值;
3、询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模 P 的值。

思路

需要记录的信息,\(L,R,add,mul\)

先加再乘很难维护信息,故先乘再加。

代码

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

}
void pushdown(int u){
    eval(tr[u<<1],tr[u].add,tr[u].mul);
    eval(tr[u<<1|1],tr[u].add,tr[u].mul);
    tr[u].add=0,tr[u].mul=1;
}
void build(int u,int l,int r){
    if(l==r) tr[u]={l,r,w[r],0,1};
    else{
        tr[u]={l,r,0,0,1};
        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 add,int mul){
    if(tr[u].l>=l && tr[u].r<=r) eval(tr[u],add,mul);
    else{
        pushdown(u);
        int mid=(tr[u].l+tr[u].r)>>1;
        if(l<=mid) modify(u<<1,l,r,add,mul);
        if(r> mid) modify(u<<1|1,l,r,add,mul);
        pushup(u);
    }
}
ll query(int u,int l,int r){
    if(tr[u].l>=l && tr[u].r<=r) return tr[u].sum;
    pushdown(u);
    ll sum=0;
    int mid=tr[u].l+tr[u].r>>1;
    if(l<=mid) sum=query(u<<1,l,r)%p;
    if(r>mid) sum=(sum+query(u<<1|1,l,r))%p;
    return sum;
}
int main(){
    cin>>n>>p;
    for(int i=1;i<=n;i++) cin>>w[i];
    build(1,1,n);
    cin>>m;
    while(m--){
        int t,l,r,d;
        scanf("%d%d%d",&t,&l,&r);
        if(t==1){
            scanf("%d",&d);
            modify(1,l,r,0,d);
        }
        else if(t==2){
            scanf("%d",&d);
            modify(1,l,r,d,1);
        }
        else{
            printf("%d\n",query(1,l,r));
        }
    }
    return 0;
}
posted @ 2021-01-24 14:46  ans20xx  阅读(38)  评论(0编辑  收藏  举报