P2023[AHOI2009]维护序列

题目描述

老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。 有长为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,按照它在输入中出现的顺序,依次输出一行一个整数表示询问结果。


不得不说,这题让我对lazy的理解加深了一步
需要考虑乘与加的优先性
我们设sum是区间和,len为区间长,(x)代表乘上或加上的值
tag1lazy_addtag2lazy_mul

如果我们先加再乘,即:(sum+tag1(ast)len)(ast)tag2**
乘法操作: (sum+tag1(ast)len)(ast)tag2(ast)x是不会有影响的,所以tar1不变,tar2相乘
加法操作 (sum+tag1(ast)len)(ast)tag2+x(ast)len
转化后 (sum+len(x(ackslash)tag2+tag1))(ast)tag2。所以这里的tar1+=x(ackslash)tag2,tar1不变

但这样tar1会出现精度问题

所以考虑先乘后加
sum(ast)tag2 (+)tag1(ast)len
乘法操作: (sum(ast)tag2 +tag1(*)len)(ast x)
很容易看出我们应该
tag1(ast)=(x),tag2(ast)=(x)
加法操作: (sum(ast)tag2 (+)tag1*len)+x(*)len
则只需要将 tar1+=(x),tar2 不变


代码

#include<bits/stdc++.h>
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
const int maxn=200000+10;
struct tag
{
	long long add,mul;
}lazy[maxn<<2];
int n,m;
long long p;
long long sum[maxn<<2];
long long res=0;
inline long long read()
{
	long long x=0,f=1;char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
	return x*f;
}
inline void pushup(int rt)
{
	sum[rt]=sum[lson]+sum[rson];
	sum[rt]%=p;
	return;
}
inline void pushdown(int rt,int m)
{
	 sum[lson]=sum[lson]*lazy[rt].mul+lazy[rt].add*(m-(m>>1));
	 sum[lson]%=p; 
	 sum[rson]=sum[rson]*lazy[rt].mul+lazy[rt].add*(m>>1);
	 sum[rson]%=p;
	 lazy[lson].add=lazy[lson].add*lazy[rt].mul+lazy[rt].add;
	 lazy[lson].add%=p;
	 lazy[rson].add=lazy[rson].add*lazy[rt].mul+lazy[rt].add;
	 lazy[rson].add%=p;
	 lazy[lson].mul*=lazy[rt].mul;
	 lazy[lson].mul%=p;
	 lazy[rson].mul*=lazy[rt].mul;
	 lazy[rson].mul%=p;
	 lazy[rt].mul=1;
	 lazy[rt].add=0;
	 return;
}
inline void build(int l,int r,int rt)
{
	lazy[rt].add=0;
	lazy[rt].mul=1;
	if(l==r)
	{
		sum[rt]=read();
		sum[rt]%=p; 
		return;
	}
	int m=(l+r)>>1;
	build(l,m,lson);
	build(m+1,r,rson);
	pushup(rt);
}
inline void update_add(int L,int R,int c,int l,int r,int rt)
{
	if(L<=l&&r<=R)
	{
		lazy[rt].add+=c;
	    lazy[rt].add%=p;
		sum[rt]+=c*(r-l+1);
		sum[rt]%=p;
		return;
	}
	pushdown(rt,r-l+1);
	int m=(l+r)>>1;
	if(L<=m)
	update_add(L,R,c,l,m,lson);
	if(m<R)
	update_add(L,R,c,m+1,r,rson);
	pushup(rt);
}
inline void update_mul(int L,int R,int c,int l,int r,int rt)
{
	if(L<=l&&r<=R)
	{
		lazy[rt].mul*=c;
		lazy[rt].mul%=p;
		lazy[rt].add*=c;
	    lazy[rt].add%=p;
		sum[rt]*=c;
		sum[rt]%=p;
		return;
	}
	pushdown(rt,r-l+1);
	int m=(l+r)>>1;
	if(L<=m)
	update_mul(L,R,c,l,m,lson);
	if(m<R)
	update_mul(L,R,c,m+1,r,rson);
	pushup(rt);
}
void query(int L,int R,int l,int r,int rt)
{
	if(L<=l&&r<=R)
	{
		res+=sum[rt];
		res%=p;
		return;
	}
	pushdown(rt,r-l+1);
	int m=(l+r)>>1;
	if(L<=m)
	query(L,R,l,m,lson);
	if(m<R)
	query(L,R,m+1,r,rson);
}
int main()
{
	n=read(),p=read();
	build(1,n,1);
	m=read();
	for(int i=1;i<=m;i++)
	{
		int op=read();
		if(op==1)
		{
			int x=read(),y=read(),k=read();
			update_mul(x,y,k,1,n,1);
		}
		if(op==2)
		{
			int x=read(),y=read(),k=read();
			update_add(x,y,k,1,n,1);	
		}
		if(op==3)
		{
			int x=read(),y=read();res=0;
			query(x,y,1,n,1);
			printf("%lld
",res);
		}
	}
	return 0;
} 
原文地址:https://www.cnblogs.com/DriverBen/p/10410701.html