[BZOJ1798] [Ahoi2009]Seq 维护序列seq
[Ahoi2009]Seq 维护序列seq
Description
老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。 有长为N的数列,不妨设为a1,a2,…,aN 。有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模P的值。
Input
第一行两个整数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)。 同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。
Output
对每个操作3,按照它在输入中出现的顺序,依次输出一行一个整数表示询问结果。
Sample Input
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
Sample Output
2
35
8
HINT
【样例说明】
初始时数列为(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。
这题建两个lazy数组,一个是加和add,另一个是乘积mul。举个栗子,(ax+b)*c+d=axc+bc+d,可以看出上一层的add(d)对本层的影响就是直接加,上一层的成绩mul(c)对本层的影响还关系到本层的add,所以是本层的mul*=上层的mul,本层的add=上层的add+本层的add(b)*上层的mul(c)。其余就是板子代码了。
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define ll long long
const int N=1e5+5;
const double eps=1e-8;
const double PI = acos(-1.0);
#define lowbit(x) (x&(-x))
#define int long long
int sum[N<<2],add[N<<2],mul[N<<2];
int a[N],n,m,p;
void pushUp(int rt)
{
sum[rt]=(sum[rt<<1]+sum[rt<<1|1])%p;
}
void build(int l,int r,int rt)
{
if(l==r)
{
sum[rt]=a[l];
return;
}
int m=(l+r)>>1;
build(l,m,rt<<1);
build(m+1,r,rt<<1|1);
pushUp(rt);
}
void pushDown(int rt,int ln,int rn)
//rt根结点
//ln左区间大小,rn为右区间大小
{
if(add[rt]||mul[rt]!=1)
{
mul[rt<<1]=(mul[rt<<1]*mul[rt])%p;
mul[rt<<1|1]=(mul[rt<<1|1]*mul[rt])%p;
add[rt<<1]=(add[rt]+add[rt<<1]*mul[rt]%p)%p;
add[rt<<1|1]=(add[rt]+add[rt<<1|1]*mul[rt]%p)%p;
sum[rt<<1]=(sum[rt<<1]*mul[rt]%p+add[rt]*ln%p)%p;
sum[rt<<1|1]=(sum[rt<<1|1]*mul[rt]%p+add[rt]*rn%p)%p;
add[rt]=0;
mul[rt]=1;
}
}
void update(int L,int R,int C,int l,int r,int rt,int o)
{
if(L <= l && r <= R)
{
if(o==1) //如果是乘法
{
sum[rt]=(sum[rt]*C)%p;
mul[rt]=(mul[rt]*C)%p;
add[rt]=(add[rt]*C)%p;
}
else //如果是加法
{
sum[rt]=(sum[rt]%p+C%p*(r-l+1)%p)%p;
add[rt]=(add[rt]+C)%p;
}
return ;
}
int m=(l+r)>>1;
pushDown(rt,m-l+1,r-m);
if(L <= m) update(L,R,C,l,m,rt<<1,o);
if(R > m) update(L,R,C,m+1,r,rt<<1|1,o);
pushUp(rt);
}
int query(int L,int R,int l,int r,int rt)
{
if(L <= l && r <= R)
{
return sum[rt];
}
int m=(l+r)>>1;
pushDown(rt,m-l+1,r-m);
int ans=0;
if(L <= m) ans+=query(L,R,l,m,rt<<1),ans%=p;
if(R > m) ans+=query(L,R,m+1,r,rt<<1|1),ans%=p;
ans%=p;
return ans;
}
signed main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
while(cin>>n>>p)
{
memset(add,0,sizeof(add));
fill(mul,mul+(N<<2),1);
for(int i=1; i<=n; i++)
{
cin>>a[i];
}
build(1,n,1);
cin>>m;
while(m--)
{
ll o,l,r,c;
cin>>o>>l>>r;
if(o==3)
{
cout<<query(l,r,1,n,1)<<endl;
}
else
{
cin>>c;
update(l,r,c,1,n,1,o);
}
}
}
return 0;
}
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
ll mod;
ll val[100001];
void read(ll &x)
{
char ch; bool ok;
for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar())
if(ch=='-') ok=1;
for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar());
if(ok) x=-x;
}
ll m,n,k,a,b;
struct Segment_Tree{
#define ls (p<<1)
#define rs (p<<1|1)
#define mid ((l+r)>>1)
ll tree[400050],cnt[400050],res[400050];
void updata(int p)
{
tree[p]=(tree[ls]+tree[rs])%mod;
}
void add_lazy(int p,int v,int r)
//p为根结点,v为权值,r为区间大小
{
tree[p]=(tree[p]+1ll*v*r)%mod;
cnt[p]=(cnt[p]+v)%mod;
}
void res_lazy(int p,int v)
{
tree[p]=1ll*tree[p]*v%mod;
res[p]=1ll*res[p]*v%mod;
//res为乘法标记
cnt[p]=1ll*cnt[p]*v%mod;
//cnt为加法标记
}
void add_pushdown(int p,int l,int r)
//加法标记下放
{
if(!cnt[p])
return;
add_lazy(ls,cnt[p],mid-l+1), //区间为[l,mid]
add_lazy(rs,cnt[p],r-mid); //区间为[mid+1,r]
cnt[p]=0;
}
void res_pushdown(int p)
//乘法标记下放
{
if(res[p]==1)
return;
res_lazy(rs,res[p]),res_lazy(ls,res[p]);
res[p]=1;
}
void pushdown(int p,int l,int r)
{
res_pushdown(p);
//先放乘法标记
add_pushdown(p,l,r);
//再放加法标记
}
void build(int p,int l,int r)
{
cnt[p]=0;
res[p]=1;
if(l==r)
{
tree[p]=val[l];
return;
}
build(ls,l,mid);
build(rs,mid+1,r);
updata(p);
}
void change(int p,int l,int r,int a,int b,int v,int v1)
{
if(l>=a&&r<=b)
{
res_lazy(p,v1);
add_lazy(p,v,r-l+1);
return;
}
pushdown(p,l,r);
if(a<=mid)
change(ls,l,mid,a,b,v,v1);
if(b>mid)
change(rs,mid+1,r,a,b,v,v1);
updata(p);
}
ll query(int p,int l,int r,int a,int b)
{
if(l>=a&&r<=b) return tree[p]%mod;
ll ans=0;
pushdown(p,l,r);
if(a<=mid)
ans=(ans+query(ls,l,mid,a,b))%mod;
if(b>mid)
ans=(ans+query(rs,mid+1,r,a,b))%mod;
return ans%mod;
}
}tree;
int main()
{
read(n),read(mod);
for(int i=1;i<=n;i++)
read(val[i]);
read(m);
tree.build(1,1,n);
for(int i=1;i<=m;i++)
{
ll a,b,c,op;read(op);
//op为1时,乘
//op为2时,加
if(op==2)
read(a),read(b),read(c),
tree.change(1,1,n,a,b,c,1);
else
if(op==1)
read(a),read(b),read(c),
tree.change(1,1,n,a,b,0,c);
else
{
read(a),read(b);
printf("%lld\n",tree.query(1,1,n,a,b)%mod);
}
}
return 0;
}

浙公网安备 33010602011771号