[BZOJ1798] [Ahoi2009]Seq 维护序列seq

[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。

const int N=1e5+3;
int n,x,y,z,T,P,op,A[N];
inline void in(Re &x){
    int f=0;x=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
struct Segment_Tree
{
    #define pl (p<<1)
    #define pr (p<<1|1)
    #define mid ((L+R)>>1)
    struct QAQ
	{
	     LL S,mul,add;
	}  tr[N<<2];
    inline void pushup(Re p)
	{
	  tr[p].S=(tr[pl].S+tr[pr].S)%P;
	}
    inline void updata1(Re p,LL v)
	{
        tr[p].S=(LL)tr[p].S*v%P,
		tr[p].mul=(LL)tr[p].mul*v%P,
		tr[p].add=(LL)tr[p].add*v%P;
    }
    inline void updata2(Re p,Re L,Re R,LL v)
	{
	     (tr[p].S+=v*(R-L+1)%P)%=P,
		 (tr[p].add+=v)%=P;
	}
    inline void pushdown(Re p,Re L,Re R)
	{
        if(tr[p].mul!=1)
		    updata1(pl,tr[p].mul),
			updata1(pr,tr[p].mul),
			tr[p].mul=1;
        if(tr[p].add)
		   updata2(pl,L,mid,tr[p].add),
		   updata2(pr,mid+1,R,tr[p].add),
		   tr[p].add=0;
    }
    inline void build(Re p,Re L,Re R)
	{
        tr[p].mul=1;
        if(L==R)
		   {
		       tr[p].S=A[L]%P;
			   return;
		   }
        build(pl,L,mid),
		build(pr,mid+1,R);
        pushup(p);
    }
    inline void change(Re p,Re L,Re R,Re l,Re r,Re v,Re op)
	{
        if(l<=L&&R<=r)
		   {if(op<2)
		   //op为1时,乘
		   //op为2时,加 
		       updata1(p,v);
			else 
			    updata2(p,L,R,v);
			return;
		   }
        pushdown(p,L,R);
        if(l<=mid)
		    change(pl,L,mid,l,r,v,op);
        if(r>mid)
		   change(pr,mid+1,R,l,r,v,op);
        pushup(p);
    }
    inline LL ask(Re p,Re L,Re R,Re l,Re r)
	{
        if(l<=L&&R<=r)
		    return tr[p].S;
        LL ans=0;
		pushdown(p,L,R);
        if(l<=mid)
		   (ans+=ask(pl,L,mid,l,r))%=P;
        if(r>mid)
		   (ans+=ask(pr,mid+1,R,l,r))%=P;
        return ans;
    }
}TR;
int main(){
    in(n),in(T),in(P);
    for(Re i=1;i<=n;++i)
	    in(A[i]);
    TR.build(1,1,n);
    while(T--)
	{
        in(op),in(x),in(y);
        if(op<3)
        
		   in(z),TR.change(1,1,n,x,y,z,op);
        else 
		   printf("%lld\n",TR.ask(1,1,n,x,y));
    }
}

  

上一篇:72.打印正方形脚本


下一篇:java多线程--启动线程