维护序列

本文介绍了如何使用树形结构处理数列的区间修改与求和问题,包括乘法、加法操作以及求和查询,并提供了一个C++实现的代码示例,该代码使用了树状数组(也称作线段树)的数据结构,能够高效地处理大规模数据并优化内存占用。
摘要由CSDN通过智能技术生成

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

有长为 nnn 的数列,不妨设为 a1,a2,⋯ ,an。有如下三种操作形式:

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

输入格式

第一行两个整数 n 和 P;

第二行含有 n 个非负整数,从左到右依次为 a1,a2,⋯ ,an​;

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

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

  • 操作 1:1 t g c,表示把所有满足 t≤i≤g 的 ai​ 改为 ai​×c;
  • 操作 2:2 t g c,表示把所有满足 t≤i≤g的 ai​ 改为 ai+c;
  • 操作 3:3 t g,询问所有满足 t≤i≤g 的 ai 的和模 P 的值。

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

输出格式

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

样例

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

数据范围与提示的要求就是数据很大,需要注意范围,要用树形结构。

思路:

树形结构。

每次结果都模一下,减小储存数据。

注意ax+b的乘法加法的优先级关系。

#include<iostream>
typedef long long ll;
using namespace std;
const int N=2e6;
int n,M;
ll P,a[N+5];
struct tree
{
	int l,r;
	ll sum,mu,ad;
}T[N*4+5];
void pushup(int k)
{
	//printf("pushup");
	T[k].sum =(T[k*2].sum +T[k*2+1].sum )%P; 
}
void pushdown(int k)
{
	//printf("pushdown");
	int len=T[k].r -T[k].l +1;
	T[k<<1].sum =(T[k<<1].sum *T[k].mu +T[k].ad *(len+1>>1))%P;
	T[k<<1|1].sum =(T[k<<1|1].sum *T[k].mu +T[k].ad *(len>>1))%P;
	T[k<<1].mu =T[k<<1].mu *T[k].mu %P;
	T[k<<1|1].mu =T[k<<1|1].mu *T[k].mu %P;
	T[k<<1].ad =(T[k<<1].ad *T[k].mu +T[k].ad )%P;
	T[k<<1|1].ad =(T[k<<1|1].ad *T[k].mu +T[k].ad )%P;
	T[k].mu =1,T[k].ad =0;
}
void build(int k,int l,int r)
{
	T[k].mu =1,T[k].ad =0;	
	//printf("build");
	T[k].l =l,T[k].r =r;
	if(l==r)
	{
		T[k].sum =a[l];
		T[k].sum %=P;
		return;
	}
	int mid=(l+r)/2;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	pushup(k); 
}
void mul(int k,int t,int g,ll c)
{
	//printf("mul");
	if(T[k].l >=t&&T[k].r <=g)
	{
		T[k].sum =T[k].sum *c%P;
		T[k].mu =T[k].mu *c%P;
		T[k].ad =T[k].ad *c%P;//foget
		return;
	}
	pushdown(k);
	int mid=(T[k].r +T[k].l )/2;
	if(t<=mid)
		mul(k<<1,t,g,c);
	if(g>mid)
		mul(k<<1|1,t,g,c);
	pushup(k); 
}
void add(int k,int t,int g,ll c)
{
	//printf("add");
	if(T[k].l >=t&&T[k].r <=g)
	{
		T[k].ad =(T[k].ad +c)%P;
		T[k].sum =(T[k].sum +c*(T[k].r -T[k].l +1))%P;
		return;
	}
	pushdown(k);
	int mid=(T[k].r +T[k].l )/2;
	if(t<=mid)
		add(k<<1,t,g,c);
	if(g>mid)
		add(k<<1|1,t,g,c);
	pushup(k);
}
ll query(int k,int t,int g)
{
	//printf("query");
	if(T[k].l>=t&&T[k].r <=g)
	{
		return T[k].sum ;
	}
	pushdown(k);
	int mid=(T[k].l +T[k].r )/2;
	ll s=0;
	if(t<=mid)
		s+=query(k<<1,t,g);
	if(g>mid)
		s+=query(k<<1|1,t,g);
	s%=P;
	return s;
}
int main()
{
	scanf("%d %lld",&n,&P);
	for(int i=1;i<=n;i++)
		scanf("%lld",&a[i]);
	build(1,1,n);
	scanf("%d",&M);
	while(M--)
	{
		//for(int i=1;i<=n*4;i++)
		//	printf("%lld %lld %lld\n",T[i].sum ,T[i].mu ,T[i].ad );
		int t=0,g=0,type=0;
		ll c=0;
		scanf("%d %d %d",&type,&t,&g);
		if(type==1)
		{
		//	printf("1");
			scanf("%lld",&c);
			mul(1,t,g,c);
		}
		else if(type==2)
		{
		//	printf("2");
			scanf("%lld",&c);
			add(1,t,g,c);
		}
		else if(type==3)
		{
		//	printf("3");
			printf("%lld\n",query(1,t,g));
		}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TherAndI

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值