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

  

 
原文地址:https://www.cnblogs.com/cutemush/p/14286556.html