M-维护序列

题目描述

原题来自:AHOI 2009

老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。

有长为 nn 的数列,不妨设为 a_1,a_2,\cdots ,a_na1​,a2​,⋯,an​。有如下三种操作形式:

  • 把数列中的一段数全部乘一个值;
  • 把数列中的一段数全部加一个值;
  • 询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模 PP 的值。

输入格式

第一行两个整数 nn 和 PP;

第二行含有 nn 个非负整数,从左到右依次为 a_1,a_2,\cdots ,a_na1​,a2​,⋯,an​;

第三行有一个整数 MM,表示操作总数;

从第四行开始每行描述一个操作,输入的操作有以下三种形式:

  • 操作 11:1 t g c,表示把所有满足 t\le i\le gt≤i≤g 的 a_iai​ 改为 a_i\times cai​×c;
  • 操作 22:2 t g c,表示把所有满足 t\le i\le gt≤i≤g 的 a_iai​ 改为 a_i+cai​+c;
  • 操作 33:3 t g,询问所有满足 t\le i\le gt≤i≤g 的 a_iai​ 的和模 PP 的值。

同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。

输出格式

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

样例

InputcopyOutputcopy
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,2,3,4,5,6,7};

经过第 11 次操作后,数列为 {1,10,15,20,25,6,7}{1,10,15,20,25,6,7};

对第 22 次操作,和为 10+15+20=4510+15+20=45,模 4343 的结果是 22;

经过第 33 次操作后,数列为 {1,10,24,29,34,15,16}{1,10,24,29,34,15,16};

对第 44 次操作,和为 1+10+24=351+10+24=35,模 4343 的结果是 3535;

对第 55 次操作,和为 29+34+15+16=9429+34+15+16=94,模 4343 的结果是 88。

数据范围与提示

对于全部测试数据,1\le t\le g\le n,0\le c,a_i\le 10^9,1\le P\le 10^9+71≤t≤g≤n,0≤c,ai​≤109,1≤P≤109+7。

测试数据规模如下表所示:

数据编号111" style="text-align:center;">112,32,32,3" style="text-align:center;">2,32,3444" style="text-align:center;">44555" style="text-align:center;">55666" style="text-align:center;">66777" style="text-align:center;">77888" style="text-align:center;">889,109,109,10" style="text-align:center;">9,109,10
n=n=101010^310310^41046\times 10^46×1047\times 10^47×1048\times 10^48×1049\times 10^49×10410^5105
M=M=101010^310310^41046\times 10^46×1047\times 10^47×1048\times 10^48×104

取模运算性质:

(a + b) % p = (a % p + b % p) % p;

 (a * b) % p = (a % p * b % p) % p;

取模:

#include<iostream>
using namespace std;
const int N=100000;
long long a[N*4+5];
long long n,p,m;
long long ans;
struct Node
{
    long long len;
    long long sum;
    long long mflag;
    long long flag;
}tree[4*N+5];
void pushdown(long rt)
{
	if(tree[rt].flag!=0||tree[rt].mflag!=1)
	{
		tree[rt*2].flag=(tree[rt].mflag*tree[rt*2].flag+tree[rt].flag)%p;
		tree[rt*2+1].flag=(tree[rt].mflag*tree[rt*2+1].flag+tree[rt].flag)%p;
		tree[rt*2].mflag*=tree[rt].mflag;
		tree[rt*2].mflag=tree[rt*2].mflag%p;
		tree[rt*2+1].mflag*=tree[rt].mflag;
		tree[rt*2+1].mflag=tree[rt*2+1].mflag%p;
		tree[rt*2].sum=tree[rt*2].sum*tree[rt].mflag%p+tree[rt].flag*tree[rt*2].len%p;
		tree[rt*2].sum=tree[rt*2].sum%p;
		tree[rt*2+1].sum=tree[rt*2+1].sum*tree[rt].mflag%p+tree[rt].flag*tree[rt*2+1].len%p;
		tree[rt*2+1].sum=tree[rt*2+1].sum%p;
		tree[rt].flag=0;
		tree[rt].mflag=1;
	}
}
void pushup(long rt)
{
	tree[rt].sum=tree[rt*2].sum+tree[rt*2+1].sum;
	tree[rt].sum%=p;
}
void build(long rt,long long l,long r)
{
	tree[rt].len=r-l+1;
	tree[rt].mflag=1;
	tree[rt].flag=0;
	if(l==r)
	{
		tree[rt].sum=a[l];
		tree[rt].sum%=p; 
		return ;
	}
	int mid=(l+r)/2;
	build(rt*2,l,mid);
	build(rt*2+1,mid+1,r);
	pushup(rt);
	return ;
}
void mul(long rt,long tl,long tr,long long l,long long r,long long c)
{
	if(tl>=l&&r>=tr)
	{
		tree[rt].mflag*=c;
		tree[rt].mflag%=p;
		tree[rt].flag*=c;
		tree[rt].flag%=p;
		tree[rt].sum*=c;
		tree[rt].sum%=p;
		return ;
	}
	pushdown(rt);
	int mid=(tr+tl)/2;
	if(mid>=l)
		mul(rt*2,tl,mid,l,r,c);
	if(mid<r)
		mul(rt*2+1,mid+1,tr,l,r,c);
	pushup(rt);
	return ;
}
void add(long rt,long tl,long tr,long long l,long long r,long long c)
{
	if(tl>=l&&r>=tr)
	{
		tree[rt].flag+=c;
		tree[rt].flag%=p;
		tree[rt].sum+=c*tree[rt].len;
		tree[rt].sum%=p;
		return ;
	}
	pushdown(rt);
	int mid=(tr+tl)/2;
	if(mid>=l)
		add(rt*2,tl,mid,l,r,c);
	if(mid<r)
		add(rt*2+1,mid+1,tr,l,r,c);
	pushup(rt);
	return ;
}
void query(long rt,long tl,long tr,long long l,long long r)
{
	if(tl>=l&&r>=tr)
	{
		ans+=tree[rt].sum;
		ans=ans%p;
		return ;
	}
	pushdown(rt);
	int mid=(tr+tl)/2;
	if(mid>=l)
		query(rt*2,tl,mid,l,r);
	if(mid<r)
		query(rt*2+1,mid+1,tr,l,r);
	return ;
}
int main()
{
	scanf("%d %d",&n,&p);
    for(int i=1;i<=n;i++)
		scanf("%lld",&a[i]);
    build(1,1,n);
    scanf("%d",&m);
    while(m--)
    {
    	int l,r,c;
    	int zl;
    	scanf("%d",&zl);
    	if(zl==1)
    	{
    		scanf("%d %d %d",&l,&r,&c);
    		mul(1,1,n,l,r,c);
		}
		else if(zl==2)
		{
			scanf("%d %d %d",&l,&r,&c);
			add(1,1,n,l,r,c);
		}
		else
		{
			scanf("%d %d",&l,&r);
			ans=0;
			query(1,1,n,l,r);
			printf("%lld\n",ans%p);
		}
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值