[Ahoi2009]Seq 维护序列seq

Description

老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。 有长为N的数列,不妨设为a1,a2,…,aN 。有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模P的值。
Input
第一行两个整数N和P(1≤P≤1000000000)。第二行含有N个非负整数,从左到右依次为a1,a2,…,aN, (0≤ai≤1000000000,1≤i≤N)。第三行有一个整数M,表示操作总数。从第四行开始每行描述一个操作,输入的操作有以下三种形式: 操作1:“1 t g c”(不含双引号)。表示把所有满足t≤i≤g的ai改为ai×c (1≤t≤g≤N,0≤c≤1000000000)。 操作2:“2 t g c”(不含双引号)。表示把所有满足t≤i≤g的ai改为ai+c (1≤t≤g≤N,0≤c≤1000000000)。 操作3:“3 t g”(不含双引号)。询问所有满足t≤i≤g的ai的和模P的值 (1≤t≤g≤N)。 同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。
Output
对每个操作3,按照它在输入中出现的顺序,依次输出一行一个整数表示询问结果。
Sample Input
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
Sample Output
2
35
8

HINT

【样例说明】
初始时数列为(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。

测试数据规模如下表所示

数据编号 1 2 3 4 5 6 7 8 9 10
N= 10 1000 1000 10000 60000 70000 80000 90000 100000 100000
M= 10 1000 1000 10000 60000 70000 80000 90000 100000 100000

分析

一道线段树板子题,我们所需要考虑的是如何处理加法与乘法的关系,因为乘法优先级高于加分,所以应先将乘法的lazy标记下移,随后下移加法的lazy标记,至于打标记和区间求和,和普通线段树几乎一样,时间:5000ms。
上代码

#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll n,m,mod,num[100010];
struct node{
    ll l,r,sum,add,mul;
}tree[400010];
void updata(ll p){
    tree[p].sum=(tree[p*2].sum+tree[p*2+1].sum)%mod;
}
void build(ll l,ll r,ll p){
    tree[p].l=l,tree[p].r=r,tree[p].mul=1;
    if(l==r){
        tree[p].sum=num[l],tree[p].mul=1;
        return ;
    }
    ll mid=(tree[p].l+tree[p].r)/2;
    build(l,mid,p*2),build(mid+1,r,p*2+1);
    updata(p);
}
void pushdown(ll p){
    ll mid=(tree[p].l+tree[p].r)/2;
    if(tree[p].mul!=1){
        tree[p*2].mul=tree[p*2].mul*tree[p].mul%mod;
        tree[p*2+1].mul=tree[p*2+1].mul*tree[p].mul%mod;
        tree[p*2].add=tree[p*2].add*tree[p].mul%mod;
        tree[p*2+1].add=tree[p*2+1].add*tree[p].mul%mod;
        tree[p*2].sum=tree[p*2].sum*tree[p].mul%mod;
        tree[p*2+1].sum=tree[p*2+1].sum*tree[p].mul%mod;
        tree[p].mul=1;
    }
    if(tree[p].add){
        tree[p*2].add=(tree[p*2].add+tree[p].add)%mod;
        tree[p*2+1].add=(tree[p*2+1].add+tree[p].add)%mod;
        tree[p*2].sum=(tree[p*2].sum+tree[p].add*(mid-tree[p].l+1)%mod)%mod;
        tree[p*2+1].sum=(tree[p*2+1].sum+tree[p].add*(tree[p].r-mid)%mod)%mod; 
        tree[p].add=0;
    }
}
void change1(ll l,ll r,ll p,ll v){
    if(tree[p].l==l&&tree[p].r==r){
        tree[p].add=(tree[p].add+v);
        tree[p].sum=(tree[p].sum+v*(r-l+1));
        return ;
    }
    pushdown(p);
    ll mid=(tree[p].l+tree[p].r)/2;
    if(r<=mid)
        change1(l,r,p*2,v);
    else if(l>mid) 
        change1(l,r,p*2+1,v);
    else
        change1(l,mid,p*2,v),change1(mid+1,r,p*2+1,v);
    updata(p);
}
void change2(ll l,ll r,ll p,ll v){
    if(tree[p].l==l&&tree[p].r==r){
        tree[p].add=(tree[p].add*v)%mod;
        tree[p].sum=(tree[p].sum*v)%mod;
        tree[p].mul=(tree[p].mul*v)%mod;
        return;
    }
    pushdown(p);
    ll mid=(tree[p].l+tree[p].r)/2;
    if(r<=mid)   
        change2(l,r,p*2,v);
    else if(l > mid) 
        change2(l,r,p*2+1,v);
    else
        change2(l,mid,p*2,v),change2(mid+1,r,p*2+1,v);
    updata(p);
}
ll ask(ll l,ll r,ll p){
    if(tree[p].l==l&&tree[p].r==r)
        return tree[p].sum;
    pushdown(p);
    ll mid=(tree[p].l+tree[p].r)/2;
    if(r<=mid)
        return ask(l,r,p*2)%mod;
    else if(l>mid)
        return ask(l,r,p*2+1)%mod;
    else
        return (ask(l,mid,p*2)%mod+ask(mid+1,r,p*2+1)%mod+mod)%mod;
}
int main(){
    scanf("%lld%lld",&n,&mod);
    for(int i=1;i<=n;i++)
        scanf("%d",&num[i]);
    build(1,n,1);
    scanf("%lld",&m);
    for(int i=1;i<=m;i++){
        ll o,x,y,k;
        scanf("%lld%lld%lld",&o,&x,&y);
        if(o==1){
            scanf("%lld",&k);
            change2(x,y,1,k);
        }
        if(o==2){
            scanf("%lld",&k);
            change1(x,y,1,k);
        }
        if(o==3)
            printf("%lld\n",ask(x,y,1)%mod);
    }
    return 0; 
}

猜你喜欢

转载自blog.csdn.net/sjzezwzy/article/details/81192322