【AHOI 2009】维护序列

【题目】

题目描述:

老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。 
有长为 N 的数列,不妨设为 a1,a2,…,aN 。有如下三种操作形式:
(1)把数列中的一段数全部乘一个值; 
(2)把数列中的一段数全部加一个值;
(3)询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模 P 的值。 

输入格式:

第一行两个整数 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)。 
同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。 

输出格式:

对每个操作 3,按照它在输入中出现的顺序,依次输出一行一个整数表示询问结果。

样例数据:

输入

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

输出

2
35
8

备注:

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

【分析】

emmm,线段树模板题,这里就不多赘述,不清楚的可以自己百度

【代码】

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
using namespace std;
int n,m,p;
int a[N],sum[4*N];
int add[4*N],mul[4*N];
void Build(int root,int l,int r)
{
	add[root]=0;
	mul[root]=1;
	if(l==r)
	{
		sum[root]=a[l];
		return;
	}
	int mid=(l+r)>>1;
	Build(root<<1,l,mid);
	Build(root<<1|1,mid+1,r);
	sum[root]=(sum[root<<1]+sum[root<<1|1])%p;
}
void Pushdown_mul(int root,int l,int r)
{
	mul[root<<1]=(1ll*mul[root<<1]*mul[root])%p;
	mul[root<<1|1]=(1ll*mul[root<<1|1]*mul[root])%p;
	add[root<<1]=(1ll*add[root<<1]*mul[root])%p;
	add[root<<1|1]=(1ll*add[root<<1|1]*mul[root])%p;
	sum[root<<1]=(1ll*sum[root<<1]*mul[root])%p;
	sum[root<<1|1]=(1ll*sum[root<<1|1]*mul[root])%p;
	mul[root]=1;
}
void Pushdown_add(int root,int l,int r)
{
	int mid=(l+r)>>1;
	add[root<<1]=(add[root<<1]+add[root])%p;
	add[root<<1|1]=(add[root<<1|1]+add[root])%p;
	sum[root<<1]=(sum[root<<1]+1ll*(mid-l+1)*add[root]%p)%p;
	sum[root<<1|1]=(sum[root<<1|1]+1ll*(r-mid)*add[root]%p)%p;
	add[root]=0;
}
void Multiply(int root,int l,int r,int x,int y,int k)
{
	if(l>=x&&r<=y)
	{
		add[root]=(1ll*add[root]*k)%p;
		mul[root]=(1ll*mul[root]*k)%p;
		sum[root]=(1ll*sum[root]*k)%p;
		return;
	}
	int mid=(l+r)>>1;
	if(mul[root]!=1)  Pushdown_mul(root,l,r);
	if(add[root]!=0)  Pushdown_add(root,l,r);
	if(x<=mid)  Multiply(root<<1,l,mid,x,y,k);
	if(y>mid)  Multiply(root<<1|1,mid+1,r,x,y,k);
	sum[root]=(sum[root<<1]+sum[root<<1|1])%p;
}
void Add(int root,int l,int r,int x,int y,int k)
{
	if(l>=x&&r<=y)
	{
		add[root]=(add[root]+k)%p;
		sum[root]=(sum[root]+1ll*(r-l+1)*k%p)%p;
		return;
	}
	int mid=(l+r)>>1;
	if(mul[root]!=1)  Pushdown_mul(root,l,r);
	if(add[root]!=0)  Pushdown_add(root,l,r);
	if(x<=mid)  Add(root<<1,l,mid,x,y,k);
	if(y>mid)  Add(root<<1|1,mid+1,r,x,y,k);
	sum[root]=(sum[root<<1]+sum[root<<1|1])%p;
}
int Query(int root,int l,int r,int x,int y)
{
	if(l>=x&&r<=y)
	  return sum[root];
	int ans=0,mid=(l+r)>>1;
	if(mul[root]!=1)  Pushdown_mul(root,l,r);
	if(add[root]!=0)  Pushdown_add(root,l,r);
	if(x<=mid)  ans=(ans+Query(root<<1,l,mid,x,y))%p;
	if(y>mid)  ans=(ans+Query(root<<1|1,mid+1,r,x,y))%p;
	return ans;
}
int main()
{
	int x,y,i,s,k;
	scanf("%d%d",&n,&p);
	for(i=1;i<=n;++i)
	  scanf("%d",&a[i]);
	Build(1,1,n);
	scanf("%d",&m);
	for(i=1;i<=m;++i)
	{
		scanf("%d",&s);
		if(s==1)
		{
			scanf("%d%d%d",&x,&y,&k);
			Multiply(1,1,n,x,y,k);
		}
		if(s==2)
		{
			scanf("%d%d%d",&x,&y,&k);
			Add(1,1,n,x,y,k);
		}
		if(s==3)
		{
			scanf("%d%d",&x,&y);
			printf("%d\n",Query(1,1,n,x,y));
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/forever_dreams/article/details/81612456