1. 程式人生 > 實用技巧 >luogu P2023 [AHOI2009] 維護序列

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;
}