https://www.luogu.org/problem/P2023
题目描述
老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。 有长为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,按照它在输入中出现的顺序,依次输出一行一个整数表示询问结果。
思路:模板题吧。使用两个 l a z y lazy lazy标记,注意乘法标记下传的时候同时要修改加法标记,加法标记不影响乘法标记。先下推乘法标记再下推加法标记。
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define eps 1e-8
#define pr pair<int,int>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
struct node
{
int l,r;
ll sum,lazy1,lazy2;
}tree[maxn<<2];
int n;
ll mod;
void down1(int i)
{
tree[i<<1].lazy1+=tree[i].lazy1,tree[i<<1|1].lazy1+=tree[i].lazy1;
tree[i<<1].sum+=tree[i].lazy1*(tree[i<<1].r-tree[i<<1].l+1);
tree[i<<1|1].sum+=tree[i].lazy1*(tree[i<<1|1].r-tree[i<<1|1].l+1);
tree[i].lazy1=0;
tree[i<<1].sum%=mod,tree[i<<1|1].sum%=mod;
tree[i<<1].lazy1%=mod,tree[i<<1|1].lazy1%=mod;
}
void down2(int i)
{
tree[i<<1].lazy1*=tree[i].lazy2,tree[i<<1|1].lazy1*=tree[i].lazy2;
tree[i<<1].lazy2*=tree[i].lazy2,tree[i<<1|1].lazy2*=tree[i].lazy2;
tree[i<<1].sum*=tree[i].lazy2,tree[i<<1|1].sum*=tree[i].lazy2;
tree[i].lazy2=1;
tree[i<<1].lazy1%=mod,tree[i<<1|1].lazy1%=mod;
tree[i<<1].lazy2%=mod,tree[i<<1|1].lazy2%=mod;
tree[i<<1].sum%=mod,tree[i<<1|1].sum%=mod;
}
void up(int i)
{
tree[i].sum=(tree[i<<1].sum+tree[i<<1|1].sum)%mod;
}
void build(int i,int l,int r)
{
tree[i].l=l,tree[i].r=r;
tree[i].sum=tree[i].lazy1=0;
tree[i].lazy2=1;
if(l==r)
{
scanf("%lld",&tree[i].sum);
tree[i].sum%=mod;
return ;
}
int mid=l+r>>1;
build(i<<1,l,mid);
build(i<<1|1,mid+1,r);
up(i);
}
void update1(int i,int l,int r,ll v)
{
if(tree[i].l==l&&tree[i].r==r)
{
tree[i].sum+=(r-l+1)*v;
tree[i].sum%=mod;
tree[i].lazy1+=v;
tree[i].lazy1%=mod;
return ;
}
if(tree[i].lazy2!=1)
down2(i);
if(tree[i].lazy1)
down1(i);
int mid=tree[i].l+tree[i].r>>1;
if(r<=mid)
update1(i<<1,l,r,v);
else if(l>mid)
update1(i<<1|1,l,r,v);
else
update1(i<<1,l,mid,v),
update1(i<<1|1,mid+1,r,v);
up(i);
}
void update2(int i,int l,int r,ll v)
{
if(tree[i].l==l&&tree[i].r==r)
{
tree[i].sum*=v;
tree[i].sum%=mod;
tree[i].lazy1*=v;
tree[i].lazy1%=mod;
tree[i].lazy2*=v;
tree[i].lazy2%=mod;
return ;
}
if(tree[i].lazy2!=1)
down2(i);
if(tree[i].lazy1)
down1(i);
int mid=tree[i].l+tree[i].r>>1;
if(r<=mid)
update2(i<<1,l,r,v);
else if(l>mid)
update2(i<<1|1,l,r,v);
else
update2(i<<1,l,mid,v),
update2(i<<1|1,mid+1,r,v);
up(i);
}
ll query(int i,int l,int r)
{
if(tree[i].l==l&&tree[i].r==r)
return tree[i].sum;
if(tree[i].lazy2!=1)
down2(i);
if(tree[i].lazy1)
down1(i);
int mid=tree[i].l+tree[i].r>>1;
if(r<=mid)
return query(i<<1,l,r);
else if(l>mid)
return query(i<<1|1,l,r);
else
return query(i<<1,l,mid)+query(i<<1|1,mid+1,r);
}
int main()
{
scanf("%d %lld",&n,&mod);
build(1,1,n);
int q;
int op,l,r;
ll v;
scanf("%d",&q);
while(q--)
{
scanf("%d %d %d",&op,&l,&r);
if(op==1)
{
scanf("%lld",&v);
update2(1,l,r,v);
}
else if(op==2)
{
scanf("%lld",&v);
update1(1,l,r,v);
}
else
printf("%lld\n",query(1,l,r)%mod);
}
return 0;
}