zoukankan      html  css  js  c++  java
  • luogu P2023 [AHOI2009] 维护序列

    luogu P2023 [AHOI2009] 维护序列

    题意:

    有一个长为 n 的数列 ({a_n}),有如下三种操作形式:
    1 格式 1 t g c,表示把所有满足 (tle ile g)(a_i) 改为 (a_i imes c) ;
    2 格式 2 t g c 表示把所有满足 (tle ile g)(a_i) 改为 (a_i+c) ;
    3 格式 3 t g 询问所有满足 (tle ile 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
    ",query(l,r,1));
            }
        }
        return 0;
    }
    
  • 相关阅读:
    JS缓存图片实例
    Windows Server 2008上安装Media Player
    [转] BizTalk Server 2010新功能介绍(一):概述
    Microsoft BizTalk ESB Toolkit 2.0
    Asp.NET导出Excel文件乱码解决若干方法
    [PM Tools]软件项目进度跟踪表v3.0
    关于Silverlight中多项目共享DLL文件的讨论
    Silverlight中的ListBox横向显示CheckBox
    设计模式.简单工厂
    Silverlight用户控件转移时产生的“元素已经是另一个元素的子元素”问题
  • 原文地址:https://www.cnblogs.com/YangKun-/p/13435271.html
Copyright © 2011-2022 走看看