luogu P2023 [AHOI2009] 维护序列
luogu P2023 [AHOI2009] 维护序列
题意:
有一个长为 n 的数列 \(\{a_n\}\),有如下三种操作形式:
1 格式 1 t g c
,表示把所有满足 \(t\le i\le g\) 的 \(a_i\) 改为 \(a_i\times c\) ;
2 格式 2 t g c
表示把所有满足 \(t\le i\le g\) 的 \(a_i\) 改为 \(a_i+c\) ;
3 格式 3 t g
询问所有满足 \(t\le i\le g\) 的 \(a_i\) 的和,由于答案可能很大,你只需输出这个数模 \(p\) 的值
思路:
第一眼看上去 ,裸线段树吧
但其实也有很多 细节
因为乘法和加法是同时存在的
所以加法与乘法的优先级就不一样,在你的程序中先算谁后算谁,答案都是不一样的
想一个事
如果对一个数先加再乘\(ans=(a+b)*c=a*c+b*c\) 对一个数先乘后加\(ans=a*b+c\)
那么在\(add\) \(mul\)标记同时存在时,先下放\(add\)标记是不对的 \(ans=(a+b)*c ,ans=(a+c)*b\)第二个式子就不对了,且无法补救
那先下放mul标记呢,对于第一个式子如果\(ans=a*c\)后让\(add*=c\),然后再下放\(add\) \(ans=a*c+b*c\) 完美 第二个式子,\(ans=a*b+c\)
那么问题就解决了,如果是加法,就直接加,如果是乘法,先把\(add*=c\)
对于push_down函数,每个儿子的\(x\),\(tree[now<<1].x=(tree[now<<1].x*tree[now].mul\%mod+(tree[now<<1].r-tree[now<<1].l+1)*tree[now].add\%mod)\%mod\);
因为对于每个\(add\),我们都是进行过处理的,所以直接去先算\(mul\)就可以,然后再加上底下的\(add\)的那些差值
//\(add\)是加法标记,\(mul\)是乘法标记,\(x\)是当前线段树维护值
说来说去 还是个裸线段树,一个\(tree[now]\)写成\(tree[now<<1]\),我debug要瞎了
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define lowbit(a) ((a) & -(a))
#define clean(a, b) memset(a, b, sizeof(a))
// const ll mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const int maxn = 2e5 + 9;
ll _;
//========================================================================
int mod,a[maxn];
struct node
{
ll l,r,x,add,mul;
}tree[maxn<<2];
void build(ll l,ll r,ll now)
{
tree[now].l=l;
tree[now].r=r;
tree[now].mul=1;
if(l==r)
{
tree[now].x=a[l]%mod;
return ;
}
ll mid=(l+r)>>1;
build(l,mid,now<<1);
build(mid+1,r,now<<1|1);
tree[now].x=(tree[now<<1].x+tree[now<<1|1].x)%mod;
}
void push_down(ll now)
{
tree[now<<1].x=(tree[now<<1].x*tree[now].mul%mod+(tree[now<<1].r-tree[now<<1].l+1)*tree[now].add%mod)%mod;
tree[now<<1|1].x=(tree[now<<1|1].x*tree[now].mul%mod+(tree[now<<1|1].r-tree[now<<1|1].l+1)*tree[now].add%mod)%mod;
tree[now<<1].mul=(tree[now<<1].mul*tree[now].mul)%mod;
tree[now<<1|1].mul=(tree[now<<1|1].mul*tree[now].mul)%mod;
tree[now<<1].add=(tree[now<<1].add*tree[now].mul+tree[now].add)%mod;
tree[now<<1|1].add=(tree[now<<1|1].add*tree[now].mul+tree[now].add)%mod;
tree[now].add=0;
tree[now].mul=1;
}
void update_add(ll l,ll r,ll now,ll c)
{
if(l==tree[now].l&&r==tree[now].r)
{
tree[now].x=(tree[now].x+c*(r-l+1)%mod)%mod;
tree[now].add=(tree[now].add+c)%mod;
return ;
}
push_down(now);
tree[now].x=(tree[now<<1].x+tree[now<<1|1].x)%mod;
ll mid=(tree[now].l+tree[now].r)>>1;
if(r<=mid) update_add(l,r,now<<1,c);
else if(l>mid) update_add(l,r,now<<1|1,c);
else
{
update_add(l,mid,now<<1,c);
update_add(mid+1,r,now<<1|1,c);
}
tree[now].x=(tree[now<<1].x+tree[now<<1|1].x)%mod;
}
void update_mul(ll l,ll r,ll now,ll c)
{
if(l==tree[now].l&&r==tree[now].r)
{
tree[now].add=(tree[now].add*c)%mod;
tree[now].mul=(tree[now].mul*c)%mod;
tree[now].x=(tree[now].x*c)%mod;
return ;
}
push_down(now);
tree[now].x=(tree[now<<1].x+tree[now<<1|1].x)%mod;
ll mid=(tree[now].l+tree[now].r)>>1;
if(r<=mid) update_mul(l,r,now<<1,c);
else if(l>mid) update_mul(l,r,now<<1|1,c);
else
{
update_mul(l,mid,now<<1,c);
update_mul(mid+1,r,now<<1|1,c);
}
tree[now].x=(tree[now<<1].x+tree[now<<1|1].x)%mod;
}
ll query(ll l,ll r,ll now)
{
if(l==tree[now].l&&r==tree[now].r)
{
return tree[now].x;
}
push_down(now);
tree[now].x=(tree[now<<1].x+tree[now<<1|1].x)%mod;
ll mid=(tree[now].l+tree[now].r)>>1;
if(r<=mid) return query(l,r,now<<1);
else if(l>mid) return query(l,r,now<<1|1);
else return (query(l,mid,now<<1)+query(mid+1,r,now<<1|1))%mod;
}
//========================================================================
int main()
{
ll n,p,op;
scanf("%lld%lld",&n,&mod);
for(ll i=1;i<=n;i++) scanf("%lld",&a[i]);
build(1,n,1);
ll q,l,r,c;
scanf("%lld",&q);
while(q--)
{
scanf("%lld",&op);
if(op==1)
{
scanf("%lld%lld%lld",&l,&r,&c);
update_mul(l,r,1,c);
}
else if(op==2)
{
scanf("%lld%lld%lld",&l,&r,&c);
update_add(l,r,1,c);
}
else
{
scanf("%lld%lld",&l,&r);
printf("%lld\n",query(l,r,1));
}
}
return 0;
}