• [BZOJ1798] [Ahoi2009]Seq 维护序列seq


    [Ahoi2009]Seq 维护序列seq
    Description
    老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成。 有长为N的数列,不妨设为a1,a2,…,aN 。有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列中的一段数的和,由于答案可能很大,你只需输出这个数模P的值。

    Input
    第一行两个整数N和P(1≤P≤1000000000)。第二行含有N个非负整数,从左到右依次为a1,a2,…,aN, (0≤ai≤1000000000,1≤i≤N)。第三行有一个整数M,表示操作总数。从第四行开始每行描述一个操作,输入的操作有以下三种形式: 操作1:“1 t g c”(不含双引号)。表示把所有满足t≤i≤g的ai改为ai×c (1≤t≤g≤N,0≤c≤1000000000)。 操作2:“2 t g c”(不含双引号)。表示把所有满足t≤i≤g的ai改为ai+c (1≤t≤g≤N,0≤c≤1000000000)。 操作3:“3 t g”(不含双引号)。询问所有满足t≤i≤g的ai的和模P的值 (1≤t≤g≤N)。 同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。

    Output
    对每个操作3,按照它在输入中出现的顺序,依次输出一行一个整数表示询问结果。

    Sample Input
    7 43

    1 2 3 4 5 6 7

    5

    1 2 5 5

    3 2 4

    2 3 7 9

    3 1 3

    3 4 7

    Sample Output
    2

    35

    8

    HINT
    【样例说明】

    初始时数列为(1,2,3,4,5,6,7)。
    经过第1次操作后,数列为(1,10,15,20,25,6,7)。
    对第2次操作,和为10+15+20=45,模43的结果是2。
    经过第3次操作后,数列为(1,10,24,29,34,15,16}
    对第4次操作,和为1+10+24=35,模43的结果是35。
    对第5次操作,和为29+34+15+16=94,模43的结果是8。

     这题建两个lazy数组,一个是加和add,另一个是乘积mul。举个栗子,(ax+b)*c+d=axc+bc+d,可以看出上一层的add(d)对本层的影响就是直接加,上一层的成绩mul(c)对本层的影响还关系到本层的add,所以是本层的mul*=上层的mul,本层的add=上层的add+本层的add(b)*上层的mul(c)。其余就是板子代码了。

    #include<bits/stdc++.h>
    using namespace std;
    #define inf 0x3f3f3f3f
    #define ll long long
    const int N=1e5+5;
    const double eps=1e-8;
    const double PI = acos(-1.0);
    #define lowbit(x) (x&(-x))
    #define int long long
    int sum[N<<2],add[N<<2],mul[N<<2];
    int a[N],n,m,p;
    void pushUp(int rt)
    {
        sum[rt]=(sum[rt<<1]+sum[rt<<1|1])%p;
    }
    void build(int l,int r,int rt)
    {
        if(l==r)
        {
            sum[rt]=a[l];
            return;
        }
        int m=(l+r)>>1;
        build(l,m,rt<<1);
        build(m+1,r,rt<<1|1);
        pushUp(rt);
    }
    void pushDown(int rt,int ln,int rn)
    //rt根结点
    //ln左区间大小,rn为右区间大小 
    {
        if(add[rt]||mul[rt]!=1)
        {
            mul[rt<<1]=(mul[rt<<1]*mul[rt])%p;
            mul[rt<<1|1]=(mul[rt<<1|1]*mul[rt])%p;
            add[rt<<1]=(add[rt]+add[rt<<1]*mul[rt]%p)%p;
            add[rt<<1|1]=(add[rt]+add[rt<<1|1]*mul[rt]%p)%p;
            sum[rt<<1]=(sum[rt<<1]*mul[rt]%p+add[rt]*ln%p)%p;
            sum[rt<<1|1]=(sum[rt<<1|1]*mul[rt]%p+add[rt]*rn%p)%p;
            add[rt]=0;
            mul[rt]=1;
        }
    }
    void update(int L,int R,int C,int l,int r,int rt,int o)
    {
        if(L <= l && r <= R)
        {
            if(o==1) //如果是乘法 
            {
                sum[rt]=(sum[rt]*C)%p;
                mul[rt]=(mul[rt]*C)%p;
                add[rt]=(add[rt]*C)%p;
            }
            else  //如果是加法 
            {
                sum[rt]=(sum[rt]%p+C%p*(r-l+1)%p)%p;
                add[rt]=(add[rt]+C)%p;
            }
            return ;
        }
        int m=(l+r)>>1;
        pushDown(rt,m-l+1,r-m);
        if(L <= m) update(L,R,C,l,m,rt<<1,o);
        if(R >  m) update(L,R,C,m+1,r,rt<<1|1,o);
        pushUp(rt);
    }
    int query(int L,int R,int l,int r,int rt)
    {
        if(L <= l && r <= R)
        {
            return sum[rt];
        }
        int m=(l+r)>>1;
        pushDown(rt,m-l+1,r-m);
        int ans=0;
        if(L <= m) ans+=query(L,R,l,m,rt<<1),ans%=p;
        if(R >  m) ans+=query(L,R,m+1,r,rt<<1|1),ans%=p;
        ans%=p;
        return ans;
    }
    signed main()
    {
        std::ios::sync_with_stdio(false);
        std::cin.tie(0);
        std::cout.tie(0);
        while(cin>>n>>p)
        {
            memset(add,0,sizeof(add));
            fill(mul,mul+(N<<2),1);
            for(int i=1; i<=n; i++)
            {
                cin>>a[i];
            }
            build(1,n,1);
            cin>>m;
            while(m--)
            {
                ll o,l,r,c;
                cin>>o>>l>>r;
                if(o==3)
                {
                    cout<<query(l,r,1,n,1)<<endl;
                }
                else
                {
                    cin>>c;
                    update(l,r,c,1,n,1,o);
                }
            }
        }
        return 0;
    }
    

      

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define ll long long
    ll mod;
    ll val[100001];
    void read(ll &x)
     {
        char ch; bool ok;
        for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) 
    	if(ch=='-') ok=1;
        for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); 
    	if(ok) x=-x;
    }
       
    ll m,n,k,a,b;
    struct Segment_Tree{
        #define ls (p<<1)
        #define rs (p<<1|1)
        #define mid ((l+r)>>1)
        ll tree[400050],cnt[400050],res[400050];
        void updata(int p)
    	{  
    	    tree[p]=(tree[ls]+tree[rs])%mod;
    	}
        void add_lazy(int p,int v,int r)
        //p为根结点,v为权值,r为区间大小 
        {
            tree[p]=(tree[p]+1ll*v*r)%mod;
            cnt[p]=(cnt[p]+v)%mod;
        }
        void res_lazy(int p,int v)
        {
            tree[p]=1ll*tree[p]*v%mod;
            res[p]=1ll*res[p]*v%mod;
            //res为乘法标记 
            cnt[p]=1ll*cnt[p]*v%mod;
            //cnt为加法标记 
        }
        void add_pushdown(int p,int l,int r)
        //加法标记下放 
        {
            if(!cnt[p]) 
    		return;
            add_lazy(ls,cnt[p],mid-l+1), //区间为[l,mid] 
    		add_lazy(rs,cnt[p],r-mid);  //区间为[mid+1,r] 
            cnt[p]=0;
        }
        void res_pushdown(int p)
        //乘法标记下放 
        {
            if(res[p]==1) 
    		   return;
            res_lazy(rs,res[p]),res_lazy(ls,res[p]);
            res[p]=1;
        }
        void pushdown(int p,int l,int r)
    	{
    	        res_pushdown(p); 
    	        //先放乘法标记 
    			add_pushdown(p,l,r);
    			//再放加法标记 
    	}
        void build(int p,int l,int r)
        {
            cnt[p]=0;
            res[p]=1;
            if(l==r) 
            {
                tree[p]=val[l];
                return;
            }
            build(ls,l,mid);
            build(rs,mid+1,r);
            updata(p);
        }
        void change(int p,int l,int r,int a,int b,int v,int v1)
        {
            if(l>=a&&r<=b)
            {
                res_lazy(p,v1);
                add_lazy(p,v,r-l+1);
                return;
            }
            pushdown(p,l,r);
            if(a<=mid) 
    		    change(ls,l,mid,a,b,v,v1);
            if(b>mid) 
    		    change(rs,mid+1,r,a,b,v,v1);
            updata(p);
        }
        ll query(int p,int l,int r,int a,int b)
        {   
            if(l>=a&&r<=b) return tree[p]%mod;
            ll ans=0;
            pushdown(p,l,r);
            if(a<=mid) 
    		    ans=(ans+query(ls,l,mid,a,b))%mod;
            if(b>mid) 
    		    ans=(ans+query(rs,mid+1,r,a,b))%mod;
            return ans%mod;
        }
         
    }tree;
    int main()
    {
        read(n),read(mod);
        for(int i=1;i<=n;i++)
            read(val[i]);
        read(m);
        tree.build(1,1,n);
        for(int i=1;i<=m;i++)
        {
            ll a,b,c,op;read(op);
             //op为1时,乘
    		   //op为2时,加 
            if(op==2) 
    		        read(a),read(b),read(c),
    				tree.change(1,1,n,a,b,c,1);
            else 
    		    if(op==1) 
    			   read(a),read(b),read(c),
    			   tree.change(1,1,n,a,b,0,c);
            else
            {
                read(a),read(b);
                printf("%lld
    ",tree.query(1,1,n,a,b)%mod);
            }
        }
        return 0;
    }
    

      

     
  • 相关阅读:
    堆栈详解
    结构体内存对齐
    const限定符
    硬盘及其分区(0819整理)
    Android编译环境搭建(0818-0819)
    wordpress导入模板数据
    git新建仓库
    android 镜像源
    js 获取浏览器可视窗口大小,滚动条高度
    jquery 获取浏览器可视窗口大小,滚动条高度
  • 原文地址:https://www.cnblogs.com/cutemush/p/14286556.html
Copyright © 2020-2023  润新知