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;
}
posted @ 2020-08-04 19:13  L·S·D  阅读(92)  评论(0编辑  收藏  举报