BZOJ1798 [Ahoi2009]维护序列seq
题目描述
老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。 有长为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,按照它在输入中出现的顺序,依次输出一行一个整数表示询问结果。
Solution
深夜刷一刷水题
线段树模版,唯一要考虑的就是加和乘的优先级
可以当模版玩一玩
#include<cstdio>
#include<cstring>
#include<iostream>
#define MAX 400000
#define LL long long
using namespace std;
LL sum[MAX],mul[MAX],add[MAX],mod;
void up_date(int cur)
{
sum[cur]=(sum[cur<<1]+sum[cur<<1|1])%mod;
}
void creat(int L,int R,int x,int y,int cur)
{
mul[cur]=1;
add[cur]=0;
sum[cur]+=y;
if (L==R) return;
int mid=(L+R)>>1;
if (x>mid) creat(mid+1,R,x,y,cur<<1|1);
else creat(L,mid,x,y,cur<<1);
up_date(cur);
}
void push_down(int cur,int l,int r,int mid)
{
if (mul[cur]==1 && add[cur]==0) return;
mul[cur<<1]=mul[cur<<1]*mul[cur]%mod;
add[cur<<1]=(add[cur<<1]*mul[cur]%mod+add[cur])%mod;
sum[cur<<1]=(sum[cur<<1]*mul[cur]%mod+add[cur]*(LL)(mid-l+1)%mod)%mod;
mul[cur<<1|1]=mul[cur<<1|1]*mul[cur]%mod;
add[cur<<1|1]=(add[cur<<1|1]*mul[cur]%mod+add[cur])%mod;
sum[cur<<1|1]=(sum[cur<<1|1]*mul[cur]%mod+add[cur]*(LL)(r-mid)%mod)%mod;
mul[cur]=1;
add[cur]=0;
return;
}
void change_mul(int L,int R,int l,int r,int x,int cur)
{
if (L>=l && R<=r)
{
mul[cur]=mul[cur]*(LL)x%mod;
add[cur]=add[cur]*(LL)x%mod;
sum[cur]=sum[cur]*(LL)x%mod;
return;
}
int mid=(L+R)>>1;
push_down(cur,L,R,mid);
if (l<=mid) change_mul(L,mid,l,r,x,cur<<1);
if (r>mid) change_mul(mid+1,R,l,r,x,cur<<1|1);
up_date(cur);
}
void change_add(int L,int R,int l,int r,int x,int cur)
{
if (L>=l && R<=r)
{
add[cur]=(add[cur]+(LL)x)%mod;
sum[cur]=(sum[cur]+(LL)(R-L+1)*x%mod)%mod;
return;
}
int mid=(L+R)>>1;
push_down(cur,L,R,mid);
if (l<=mid) change_add(L,mid,l,r,x,cur<<1);
if (r>mid) change_add(mid+1,R,l,r,x,cur<<1|1);
up_date(cur);
}
LL ask(int L,int R,int l,int r,int cur)
{
if (L>=l && R<=r) return sum[cur];
int mid=(L+R)>>1;
LL ans=0;
push_down(cur,L,R,mid);
if (l<=mid) ans=(ans+ask(L,mid,l,r,cur<<1))%mod;
if (r>mid) ans=(ans+ask(mid+1,R,l,r,cur<<1|1))%mod;
up_date(cur);
return ans;
}
int main()
{
// freopen("bzoj1798.in","r",stdin);
int n,m,a,b,c,i,x;
scanf("%d%lld",&n,&mod);
for (i=1;i<=n;i++) scanf("%d",&a),creat(1,n,i,a%mod,1);
scanf("%d",&m);
for (i=1;i<=m;i++)
{
scanf("%d",&x);
if (x==1) scanf("%d%d%d",&a,&b,&c),change_mul(1,n,a,b,c%mod,1);
if (x==2) scanf("%d%d%d",&a,&b,&c),change_add(1,n,a,b,c%mod,1);
if (x==3) scanf("%d%d",&a,&b),printf("%lld\n",ask(1,n,a,b,1));
for(int j=1;j<=n<<1;++j) printf("%lld ",add[j]);
puts("");
}
return 0;
}