zoukankan      html  css  js  c++  java
  • 洛谷 2023 [AHOI2009]维护序列

    洛谷 2023 [AHOI2009]维护序列

     洛谷原题传送门

        这个题也是一道经典的线段树模版(其实洛谷的模版二改一下输入顺序就能AC),其中包括区间乘法修改、区间加法修改、区间查询三个操作。

     线段树的基本操作就不再赘述了,建树,查询,修改,都比较简单,我们可以为两种操作的懒惰标记申请两个变量来记录,这道题的主要难点是down操作和两种修改的优先级问题。

     这两个问题其实就是一回事:首先当我们下推标记时,如果该点加法标记不为0且乘法标记不为1(乘法标记初始化为1),那我们应该先推哪个标记呢?

     实际上我们应该先推位置靠前(也就是比较早输入)的运算,可是运用懒惰标记后,我们是难以判断那个运算输入的更早。

     有一种解决方法就是在每次乘法修改时,将对应位置的加法懒惰标记乘以修改值。这样我们保证了每次下推标记时必然是乘法优先。

    if(tree[u].l>=x&&tree[u].r<=y)
        {
            tree[u].w*=c;
            tree[u].w%=mod;
            tree[u].mu=(tree[u].mu*c)%mod;
            tree[u].ad=(tree[u].ad*c)%mod;
            return;
        }

    这里的模运算的性质:

    ((a*b) % p * c)% p = (a * (b*c) % p) % p 

    (a * b) % p = (b * a) % p 

    我们可以随时对程序里的标记和值做模运算。

    而下推标记时,我们只要保证乘法优先,就可以轻松打出代码:

    void down(int u)
    {
        tree[u<<1].w=(tree[u<<1].w*tree[u].mu%mod+tree[u].ad*(tree[u<<1].r-tree[u<<1].l+1)%mod)%mod;
        tree[u<<1|1].w=(tree[u<<1|1].w*tree[u].mu%mod+tree[u].ad*(tree[u<<1|1].r-tree[u<<1|1].l+1)%mod)%mod;
        tree[u<<1].mu=tree[u].mu*tree[u<<1].mu%mod;
        tree[u<<1|1].mu=tree[u].mu*tree[u<<1|1].mu%mod;
        tree[u<<1].ad=(tree[u].ad+tree[u<<1].ad*tree[u].mu)%mod;   //下推时加法标记也要做乘法运算
        tree[u<<1|1].ad=(tree[u].ad+tree[u<<1|1].ad*tree[u].mu)%mod;
        tree[u].ad=0;   //清空标记
        tree[u].mu=1;
    }

    下附完整AC代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int MAXN=100010;
    typedef long long ll;
    
    struct segtree{
        int l;
        int r;
        ll w;
        ll ad;
        ll mu;
    }tree[MAXN<<2];
    
    int n,m,q,x,y;
    
    ll mod,c,ans;
    
    ll read()
    {
        ll x=0;
        int k=1;
        char c=getchar();
        while(c>'9'||c<'0')
        {
            if(c=='-') k=-1;
            c=getchar();
        }
        while(c<='9'&&c>='0')
            x=x*10+c-'0',
            c=getchar();
        return k*x;
    }
    
    void build(int u,int l,int r)
    {
        tree[u].l=l;
        tree[u].r=r;
        tree[u].ad=0;
        tree[u].mu=1;
        if(l==r)
        {
            tree[u].w=read()%mod;
            return;
        }
        int mid=(l+r)>>1;
        build(u<<1,l,mid);
        build(u<<1|1,mid+1,r);
        tree[u].w=(tree[u<<1].w+tree[u<<1|1].w)%mod;
        return;
    }
    
    void down(int u)
    {
        tree[u<<1].w=(tree[u<<1].w*tree[u].mu%mod+tree[u].ad*(tree[u<<1].r-tree[u<<1].l+1)%mod)%mod;
        tree[u<<1|1].w=(tree[u<<1|1].w*tree[u].mu%mod+tree[u].ad*(tree[u<<1|1].r-tree[u<<1|1].l+1)%mod)%mod;
        tree[u<<1].mu=tree[u].mu*tree[u<<1].mu%mod;
        tree[u<<1|1].mu=tree[u].mu*tree[u<<1|1].mu%mod;
        tree[u<<1].ad=(tree[u].ad+tree[u<<1].ad*tree[u].mu)%mod;
        tree[u<<1|1].ad=(tree[u].ad+tree[u<<1|1].ad*tree[u].mu)%mod;
        tree[u].ad=0;
        tree[u].mu=1;
    }
    
    void query(int u)
    {
        if(tree[u].l>=x&&tree[u].r<=y)
        {
            ans=(ans+tree[u].w)%mod;
            return;
        }
        down(u);
        int mid=(tree[u].l+tree[u].r)>>1;
        if(x<=mid) query(u<<1);
        if(y>mid) query(u<<1|1);
        return; 
    }
    
    void mul(int u)
    {
        if(tree[u].l>=x&&tree[u].r<=y)
        {
            tree[u].w*=c;
            tree[u].w%=mod;
            tree[u].mu=(tree[u].mu*c)%mod;
            tree[u].ad=(tree[u].ad*c)%mod;
            return;
        }
        down(u);
        int mid=(tree[u].l+tree[u].r)>>1;
        if(x<=mid) mul(u<<1);
        if(y>mid) mul(u<<1|1);
        tree[u].w=(tree[u<<1].w+tree[u<<1|1].w)%mod;
        return;
    }
    
    void add(int u)
    {
        if(tree[u].l>=x&&tree[u].r<=y)
        {
            tree[u].ad=(tree[u].ad+c)%mod;
            tree[u].w+=(tree[u].r-tree[u].l+1)*c;
            tree[u].w%=mod;
            return;
        }
        down(u);
        int mid=(tree[u].l+tree[u].r)>>1;
        if(x<=mid) add(u<<1);
        if(y>mid) add(u<<1|1);
        tree[u].w=(tree[u<<1].w+tree[u<<1|1].w)%mod;
        return;
    }
    
    int main()
    {
        n=read();
        mod=read();
        build(1,1,n);
        m=read();
        for(int i=1;i<=m;++i)
        {
            q=read();
            x=read();
            y=read();
            if(q==1)
            {
                c=read();
                mul(1);
            }
            if(q==2)
            {
                c=read();
                add(1);
            }
            if(q==3)
            {
                ans=0;
                query(1);
                printf("%lld
    ",ans%mod);
            } 
        }
       return 0; }
  • 相关阅读:
    Java spring自查笔记
    C#设置IP地址 用WMI
    idea换成护眼色
    WPF布局的6种面板
    spring注解
    c# 播放mp3
    Python 提示 “No matching distribution found for MySQLdb”
    Python3链接数据库报错:Connection.__init__() takes 1 positional argument but 5 positional arguments (and 1 keywordonly argument) were given
    安装Mysql数据库及配置相关环境变量
    Python中文件命名的注意事项
  • 原文地址:https://www.cnblogs.com/yanyiming10243247/p/9284379.html
Copyright © 2011-2022 走看看