【BZOJ】1798 [Ahoi2009]Seq 维护序列seq 线段树

80 篇文章 1 订阅
14 篇文章 0 订阅

题目传送门
这题的正解是线段树,这个其实还是比较好想的,因为这道题中的所有操作都是线段树的基本操作。
但是,这题的延迟标记有两个,这两个标记之间的关系是比较难想的,而且也是比较容易打错的……
这道题主要考察的是选手对于线段树的延迟标记的理解程度,整个程序最难打的也就是pushdown这个函数,我也在这个函数上WA了好几次。(这仅代表个人意见,如有同学认为这个函数好打,那你厉害了)

附上AC代码:

#include <cstdio>
#define lt (k<<1)
#define rt (k<<1|1)
#define mid (l+r>>1)
using namespace std;

struct note{
    long long jia,cheng,w;
}t[300010];
long long n,m,p,x,y,o,c,cheng,jia;

void build(long long k,long long l,long long r){
    t[k].jia=0,t[k].cheng=1;
    if (l==r){
        scanf("%lld",&t[k].w),t[k].w%=p;
        return;
    }
    build(lt,l,mid);
    build(rt,mid+1,r);
    t[k].w=(t[lt].w+t[rt].w)%p;
    return;
}

void push(long long k,long long l,long long r){
    t[lt].w=(t[lt].w*t[k].cheng+(mid-l+1)*t[k].jia)%p;
    t[lt].cheng=t[lt].cheng*t[k].cheng%p;
    t[lt].jia=(t[lt].jia*t[k].cheng+t[k].jia)%p;

    t[rt].w=(t[rt].w*t[k].cheng+(r-mid)*t[k].jia)%p;
    t[rt].cheng=t[rt].cheng*t[k].cheng%p;
    t[rt].jia=(t[rt].jia*t[k].cheng+t[k].jia)%p;

    t[k].cheng=1,t[k].jia=0;return;
}

void change(long long k,long long l,long long r,long long ql,long long qr){
    if (l>qr||r<ql) return;
    if (l>=ql&&r<=qr){
        t[k].w=(t[k].w*cheng+(r-l+1)*jia)%p;
        t[k].cheng=t[k].cheng*cheng%p;
        t[k].jia=(t[k].jia*cheng+jia)%p;
        return;
    }
    push(k,l,r);
    if (ql<=mid) change(lt,l,mid,ql,qr);
    if (qr>mid) change(rt,mid+1,r,ql,qr);
    t[k].w=(t[lt].w+t[rt].w)%p;
    return;
}

long long query(long long k,long long l,long long r,long long ql,long long qr){
    if (l>qr||r<ql) return 0;
    if (l>=ql&&r<=qr) return t[k].w%p;
    push(k,l,r);
    long long ans=0;
    if (ql<=mid) ans=(ans+query(lt,l,mid,ql,qr))%p;
    if (qr>mid) ans=(ans+query(rt,mid+1,r,ql,qr))%p;
    return ans%p;
}

int main(void){
    scanf("%lld%lld",&n,&p);
    build(1,1,n);
    scanf("%lld",&m);
    for (long long i=1; i<=m; ++i){
        scanf("%lld%lld%lld",&o,&x,&y);
        switch (o){
            case 1:scanf("%lld",&cheng),jia=0,change(1,1,n,x,y);break;
            case 2:scanf("%lld",&jia),cheng=1,change(1,1,n,x,y);break;
            case 3:printf("%lld\n",query(1,1,n,x,y));break;
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值