luogu P2023 [AHOI2009] 維護序列
阿新 • • 發佈:2020-08-04
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\)
因為對於每個\(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;
}