(1798: [Ahoi2009]Seq 维护序列seq)<线段树乘法操作>

来源:互联网 发布:怎么遍历json数组 编辑:程序博客网 时间:2024/05/20 22:35

题目

Time Limit: 30 Sec
Memory Limit: 64 MB

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

题解

  • 裸线段树+特殊乘法操作
  • 乘法和加法各一个标记
  • 更新的时候,如果是加操作,直接套用裸线段树的模式
    如果是乘操作,则既要把乘的标记乘v,加的标记也要乘v,简单说就是先乘后加,原理是乘法分配律
    (a+b)*v=a*v+b*v,其中a是原数,b是加的标记,v是此时乘的数
  • pushdown时并起来就好了
  • 另外记得随时取模

代码

#include<iostream>#include<cstring>#include<algorithm>#include<cstdio>using namespace std;const int M=100010;int n,p,m;struct node{    int L,R;    long long sum,c1,c2;//c1 >- *     c2 >- +}t[M*4+5];long long x;void pushup(int pos){    t[pos].sum=(t[pos<<1].sum+t[pos<<1|1].sum)%p;}void build(int pos,int L,int R){    t[pos].L=L;    t[pos].R=R;    t[pos].sum=t[pos].c2=0;    t[pos].c1=1;//初始化为1    if(L==R){        scanf("%lld",&x);        t[pos].sum=(x%p);    }    else{        int mid=(L+R)>>1;        build(pos<<1,L,mid);        build(pos<<1|1,mid+1,R);        pushup(pos);    }}void pushdown(int pos){    if(t[pos].c1==1&&t[pos].c2==0) return;    int L1=t[pos<<1].R-t[pos<<1].L+1;    int L2=t[pos<<1|1].R-t[pos<<1|1].L+1;    t[pos<<1].c1=(t[pos].c1*t[pos<<1].c1)%p;    t[pos<<1|1].c1=(t[pos].c1*t[pos<<1|1].c1)%p;    t[pos<<1].c2=(t[pos].c1*t[pos<<1].c2+t[pos].c2)%p;    t[pos<<1|1].c2=(t[pos].c1*t[pos<<1|1].c2+t[pos].c2)%p;    t[pos<<1].sum=(t[pos<<1].sum*t[pos].c1+L1*t[pos].c2)%p;    t[pos<<1|1].sum=(t[pos<<1|1].sum*t[pos].c1+L2*t[pos].c2)%p;    t[pos].c1=1;    t[pos].c2=0;}void update1(int pos,int ll,int rr,int v){    int L=t[pos].L;    int R=t[pos].R;    if(ll>R||rr<L) return;    if(ll<=L&&rr>=R){        t[pos].c1=(t[pos].c1*v)%p;         t[pos].c2=(t[pos].c2*v)%p;        t[pos].sum=(t[pos].sum*v)%p;        return;    }    pushdown(pos);    update1(pos<<1,ll,rr,v);    update1(pos<<1|1,ll,rr,v);    pushup(pos);}void update2(int pos,int ll,int rr,int v){    int L=t[pos].L;    int R=t[pos].R;    if(ll>R||rr<L) return;    if(ll<=L&&rr>=R){        t[pos].c2=(t[pos].c2+v)%p;        t[pos].sum=(t[pos].sum+(R-L+1)*v)%p;        return;    }    pushdown(pos);    update2(pos<<1,ll,rr,v);    update2(pos<<1|1,ll,rr,v);    pushup(pos);}long long query(int pos,int ll,int rr){    int L=t[pos].L;    int R=t[pos].R;    if(ll>R||rr<L) return 0;    if(ll<=L&&rr>=R) return t[pos].sum%p;    pushdown(pos);    return (query(pos<<1,ll,rr)+query(pos<<1|1,ll,rr))%p;}int main(){    scanf("%d%d",&n,&p);    build(1,1,n);    scanf("%d",&m);    int op,a,b,z;    for(int i=1;i<=m;++i){        scanf("%d",&op);        if(op==1){            scanf("%d%d%d",&a,&b,&z);            update1(1,a,b,z);        }        if(op==2){            scanf("%d%d%d",&a,&b,&z);            update2(1,a,b,z);        }        if(op==3){            scanf("%d%d",&a,&b);            printf("%lld\n",query(1,a,b)%p);        }    }    return 0;}
阅读全文
0 1
原创粉丝点击