码迷,mamicode.com
首页 > 其他好文 > 详细

P2023 [AHOI2009]维护序列 (线段树区间修改查询)

时间:2019-07-25 23:26:27      阅读:113      评论:0      收藏:0      [点我收藏+]

标签:ref   type   else   main   pre   lld   lse   i++   turn   

题目链接:https://www.luogu.org/problemnew/show/P2023

一道裸的线段树区间修改题,懒惰数组注意要先乘后加

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxx = 400010;
LL tree[maxx],lazy1[maxx],lazy2[maxx],a[maxx],mod;
int n;
void build(int l,int r,int temp)
{
    lazy1[temp]=1;lazy2[temp]=0;
    if(l==r)
    {
        tree[temp]=a[l]%mod;
        return;
    }
    int mid=(l+r)/2;
    build(l,mid,temp*2);
    build(mid+1,r,temp*2+1);
    tree[temp]=(tree[temp*2]+tree[temp*2+1])%mod;
}
void pushdown(int l,int r,int temp)
{
    //lazy1[temp*2]=a0,lazy2[temp*2]=b0,lazy1[temp]=a
    //a0*x+b0->a*(a0*x+b0)->a*a0*x+a*b0
    tree[temp*2]=(tree[temp*2]*lazy1[temp]+l*lazy2[temp])%mod;
    tree[temp*2+1]=(tree[temp*2+1]*lazy1[temp]+r*lazy2[temp])%mod;
    lazy1[temp*2]=(lazy1[temp*2]*lazy1[temp])%mod;
    lazy1[temp*2+1]=(lazy1[temp*2+1]*lazy1[temp])%mod;
    lazy2[temp*2]=(lazy2[temp*2]*lazy1[temp]+lazy2[temp])%mod;
    lazy2[temp*2+1]=(lazy2[temp*2+1]*lazy1[temp]+lazy2[temp])%mod;
    lazy1[temp]=1;lazy2[temp]=0;
}
void add1(int l,int r,int p,int q,LL c,int temp)
{
    if(p<=l&&r<=q)
    {
        tree[temp]=(tree[temp]*c)%mod;
        lazy1[temp]=(lazy1[temp]*c)%mod;
        lazy2[temp]=(lazy2[temp]*c)%mod;//注意这里,乘的发生改变加的就要改变
        return;
    }
    int mid=(l+r)/2;
    pushdown(mid-l+1,r-mid,temp);
    if(mid>=p)add1(l,mid,p,q,c,temp*2);
    if(mid<q)add1(mid+1,r,p,q,c,temp*2+1);
    tree[temp]=(tree[temp*2]+tree[temp*2+1])%mod;
}
void add2(int l,int r,int p,int q,LL c,int temp)
{
    if(p<=l&&r<=q)
    {
        tree[temp]=(tree[temp]+(r-l+1)*c)%mod;
        lazy2[temp]=(lazy2[temp]+c)%mod;
        return;
    }
    int mid=(l+r)/2;
    pushdown(mid-l+1,r-mid,temp);
    if(mid>=p)add2(l,mid,p,q,c,temp*2);
    if(mid<q)add2(mid+1,r,p,q,c,temp*2+1);
    tree[temp]=(tree[temp*2]+tree[temp*2+1])%mod;
}
LL get(int l,int r,int p,int q,int temp)
{
    if(p<=l&&r<=q)return tree[temp];
    int mid=(l+r)/2;
    LL res=0;
    pushdown(mid-l+1,r-mid,temp);
    if(mid>=p)res=(res+get(l,mid,p,q,temp*2))%mod;
    if(mid<q)res=(res+get(mid+1,r,p,q,temp*2+1))%mod;
    return res;
}
int main()
{
    scanf("%d %lld",&n,&mod);
    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    build(1,n,1);
    int m,s,t,g;
    LL c;
    scanf("%d",&m);
    while(m--)
    {
        scanf("%d",&s);
        if(s==1)
        {
            scanf("%d%d%lld",&t,&g,&c);
            add1(1,n,t,g,c,1);
        }
        else if(s==2)
        {
            scanf("%d%d%lld",&t,&g,&c);
            add2(1,n,t,g,c,1);
        }
        else
        {
            scanf("%d%d",&t,&g);
            LL ans=get(1,n,t,g,1);
            printf("%lld\n",ans);
        }
    }
    return 0;
}

P2023 [AHOI2009]维护序列 (线段树区间修改查询)

标签:ref   type   else   main   pre   lld   lse   i++   turn   

原文地址:https://www.cnblogs.com/HooYing/p/11247399.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!