题目描述
原题来自:AHOI 2009
老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。
有长为 的数列,不妨设为 。有如下三种操作形式:
输入格式
第一行两个整数 n和 P;
第二行含有 n个非负整数,从左到右依次为 ai ;
第三行有一个整数M ,表示操作总数;
从第四行开始每行描述一个操作,输入的操作有以下三种形式:
1 t g c
,表示把所有满足 t<= i <= g的 ai 改为 ai * c;2 t g c
,表示把所有满足 t<= i <= g 的 ai 改为 ai + c ;3 t g
,询问所有满足 t<= i <= g 的 ai 的和模 P的值。同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。
输出格式
对每个操作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
题目链接:https://loj.ac/problem/10129
思路:线段树,因为有两种操作,所以要特殊处理一下:
对于加法来说是和以前一样,用add懒惰标记,但对于乘法的话,不仅要对树上节点乘,同时也要对add进行乘法,这样才能保证结果是正确的。
AC代码:
#include
#define ll long long
#define N 400010
using namespace std;
ll mod,Sum[N],add[N],mul[N];
void init()
{
for(int i=1;i>1;
build(l,mid,o<<1);
build(mid+1,r,o<<1|1);
Sum[o]=(Sum[o<<1]+Sum[o<<1|1])%mod;
}
void pushdown(int o,int len)
{
if(add[o]||mul[o]!=1)
{
int lson=o<<1;
int rson=o<<1|1;
Sum[lson]=Sum[lson]*mul[o]%mod;
Sum[rson]=Sum[rson]*mul[o]%mod;
Sum[lson]=(Sum[lson]+add[o]*(len-(len>>1)))%mod;
Sum[rson]=(Sum[rson]+add[o]*(len>>1))%mod;
mul[lson]=mul[lson]*mul[o]%mod;
mul[rson]=mul[rson]*mul[o]%mod;
add[lson]=add[lson]*mul[o]%mod;
add[rson]=add[rson]*mul[o]%mod;
add[lson]=(add[lson]+add[o])%mod;
add[rson]=(add[rson]+add[o])%mod;
add[o]=0,mul[o]=1;
}
}
void update(int x,int y,int l,int r,int o,ll c,int flag)
{
if(l>=x&&r<=y)
{
if(flag)
{
Sum[o]=Sum[o]*c%mod;
add[o]=add[o]*c%mod;
mul[o]=mul[o]*c%mod;
}
else
{
Sum[o]=(Sum[o]+c*(r-l+1))%mod;
add[o]=(add[o]+c)%mod;
}
return;
}
pushdown(o,r-l+1);
int mid=(l+r)>>1;
if(x<=mid)update(x,y,l,mid,o<<1,c,flag);
if(y>mid)update(x,y,mid+1,r,o<<1|1,c,flag);
Sum[o]=(Sum[o<<1]+Sum[o<<1|1])%mod;
}
ll query(int x,int y,int l,int r,int o)
{
if(l>=x&&r<=y)
return Sum[o];
pushdown(o,r-l+1);
int mid=(l+r)>>1;
ll sum=0;
if(x<=mid)sum=(sum+query(x,y,l,mid,o<<1))%mod;
if(y>mid)sum=(sum+query(x,y,mid+1,r,o<<1|1))%mod;
return sum;
}
int main()
{
init();
int n;
scanf("%d%lld",&n,&mod);
build(1,n,1);
int m;
scanf("%d",&m);
while(m--)
{
int op,l,r;
ll c;
scanf("%d",&op);
if(op==1)
{
scanf("%d%d%lld",&l,&r,&c);
update(l,r,1,n,1,c,1);
}
else if(op==2)
{
scanf("%d%d%lld",&l,&r,&c);
update(l,r,1,n,1,c,0);
}
else
{
scanf("%d%d",&l,&r);
printf("%lld\n",query(l,r,1,n,1));
}
}
return 0;
}