7
27
2015
0

1798: [Ahoi2009]Seq 维护序列seq

1798: [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

 

双标记线段树

蒟蒻wy表示被输出用的lld坑了一个下午。。。

#include<cstdio>
int N,M,L,R;
long long P,Mul,Add;
long long add[500001];
long long mul[500001];
long long sum[500001];
void Up(int k){
	sum[k]=(sum[k*2]+sum[k*2+1])%P;
}
void Insert(int k,int l,int r){
    add[k]=0;
    mul[k]=1;
    if (l==r){
		scanf("%lld",&sum[k]);
		sum[k]%=P;
		return;
    }
    int mid=(l+r)/2;
    Insert(k*2,l,mid);
    Insert(k*2+1,mid+1,r);
    Up(k);
}
void Down(int k,int l,int r){
	int mid=(l+r)/2;
	sum[k*2]=(sum[k*2]*mul[k]+add[k]*(long long)(mid-l+1))%P;
	sum[k*2+1]=(sum[k*2+1]*mul[k]+add[k]*(long long)(r-mid))%P;
	mul[k*2]=mul[k*2]*mul[k]%P;
	mul[k*2+1]=mul[k*2+1]*mul[k]%P;
	add[k*2]=(add[k*2]*mul[k]+add[k])%P;
	add[k*2+1]=(add[k*2+1]*mul[k]+add[k])%P;
    mul[k]=1; add[k]=0;
}
void Change(int k,int l,int r){		
	if (r<L||R<l)return;
	if (L<=l&&r<=R){
		sum[k]=(sum[k]*Mul+Add*(r-l+1))%P;
		mul[k]=mul[k]*Mul%P;
		add[k]=(add[k]*Mul+Add)%P;
		return;
	}
	Down(k,l,r);
	int mid=(l+r)/2;
	Change(k*2,l,mid);
	Change(k*2+1,mid+1,r);
	Up(k);
}
long long Sum(int k,int l,int r){
	if (r<L||R<l)return 0;
	if (L<=l&&r<=R)return sum[k];
	Down(k,l,r);
	int mid=(l+r)/2;
    long long s=(Sum(k*2,l,mid)+Sum(k*2+1,mid+1,r))%P;
    Up(k);
    return s;
}
int main(){
    scanf("%d%lld",&N,&P);
    Insert(1,1,N);
    scanf("%d",&M);
    for (;M--;){
		int opt;
		scanf("%d%d%d",&opt,&L,&R);
		if (opt==1){
			scanf("%lld",&Mul);
			Add=0;
			Change(1,1,N);
		}
		if (opt==2){
			scanf("%lld",&Add);
			Mul=1;
			Change(1,1,N);
		}
		if (opt==3)
		    printf("%lld\n",Sum(1,1,N));		
    }
}
Category: BZOJ | Tags: 线段树 bzoj | Read Count: 243

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com