BZOJ1798 维护序列Seq

本文介绍了一种使用线段树解决区间加和区间乘问题的方法,并提供了一个具体的题目示例——BZOJ1798 维护序列Seq。通过该示例,展示了如何实现线段树的更新、查询等操作。

BZOJ1798 维护序列Seq

题目传送门

题解

比较简单的支持区间加和区间乘的线段树,注意\(pushdown\)的时候区间加和区间乘的处理即可。

code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
bool Finish_read;
template<class T>inline void read(T &x){Finish_read=0;x=0;int f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;if(ch==EOF)return;ch=getchar();}while(isdigit(ch))x=x*10+ch-'0',ch=getchar();x*=f;Finish_read=1;}
template<class T>inline void print(T x){if(x/10!=0)print(x/10);putchar(x%10+'0');}
template<class T>inline void writeln(T x){if(x<0)putchar('-');x=abs(x);print(x);putchar('\n');}
template<class T>inline void write(T x){if(x<0)putchar('-');x=abs(x);print(x);}
/*================Header Template==============*/
const int maxn=2e5+5;
#define ls(o) o<<1
#define rs(o) (o<<1|1)
int n,m;
ll p;
int a[maxn];
struct node {
    int l,r,sz;
    ll val;
    ll addtag,multag;
}t[maxn<<2];
/*==================Define Area================*/
namespace SegmentTree {
    void update(int o) {
        t[o].val=(t[ls(o)].val+t[rs(o)].val)%p;
    }

    void pushdown(int o) {
        if(t[o].multag!=1) {
            t[ls(o)].multag*=t[o].multag;t[ls(o)].multag%=p;
            t[rs(o)].multag*=t[o].multag;t[rs(o)].multag%=p;
            t[ls(o)].addtag*=t[o].multag;t[ls(o)].addtag%=p;
            t[rs(o)].addtag*=t[o].multag;t[rs(o)].addtag%=p;
            t[ls(o)].val*=t[o].multag;t[ls(o)].val%=p;
            t[rs(o)].val*=t[o].multag;t[rs(o)].val%=p;
            t[o].multag=1;
        }
        if(t[o].addtag) {
            t[ls(o)].addtag+=t[o].addtag;t[ls(o)].addtag%=p;
            t[rs(o)].addtag+=t[o].addtag;t[rs(o)].addtag%=p;
            t[ls(o)].val+=t[o].addtag*t[ls(o)].sz;t[ls(o)].val%=p;
            t[rs(o)].val+=t[o].addtag*t[rs(o)].sz;t[rs(o)].val%=p;
            t[o].addtag=0;
        }
        return ;
    } 

    void Build(int o,int l,int r) {
        t[o].l=l,t[o].r=r;t[o].sz=r-l+1;t[o].multag=1;
        if(t[o].l==t[o].r) {
            t[o].val=a[l];
            return ;
        }
        int mid=(l+r)>>1;
        Build(ls(o),l,mid);
        Build(rs(o),mid+1,r);
        update(o);
    } 

    ll IntervalSum(int o,int l,int r) {
        if(t[o].l>r||t[o].r<l) return 0;
        if(t[o].l>=l&&t[o].r<=r) {
            pushdown(o);
            return t[o].val;
        }
        pushdown(o);
        ll ans=0;
        int mid=(t[o].l+t[o].r)>>1;
        if(mid>=l) ans+=IntervalSum(ls(o),l,r),ans%=p;
        if(mid<=r) ans+=IntervalSum(rs(o),l,r),ans%=p;
        return ans; 
    }

    void IntervalAdd(int o,int l,int r,int v) {
        if(t[o].l>r||t[o].r<l) return ;
        if(t[o].l>=l&&t[o].r<=r) {
            t[o].val+=t[o].sz*v;
            t[o].addtag+=v;
            t[o].addtag%=p;
            t[o].val%=p;
            return ;
        }
        pushdown(o);
        int mid=(t[o].l+t[o].r)>>1;
        if(mid>=l) IntervalAdd(ls(o),l,r,v);
        if(mid<=r) IntervalAdd(rs(o),l,r,v);
        update(o);
        return ;       
    }

    void IntervalMul(int o,int l,int r,int v) {
        if(t[o].l>r||t[o].r<l) return ;
        if(t[o].l>=l&&t[o].r<=r) {
            pushdown(o);
            t[o].val*=v;t[o].val%=p;
            t[o].addtag*=v;t[o].addtag%=p;
            t[o].multag*=v;t[o].multag%=p;
            return ;
        }
        pushdown(o);
        int mid=(t[o].l+t[o].r)>>1;
        if(mid>=l) IntervalMul(ls(o),l,r,v);
        if(mid<=r) IntervalMul(rs(o),l,r,v);
        update(o);
        return ;   
    }
}
using namespace SegmentTree;

int main() {
    read(n);read(p);
    for(int i=1;i<=n;i++) {
        read(a[i]);
    }
    read(m);
    Build(1,1,n);
    for(int i=1;i<=m;i++) {
        int opt;
        read(opt);
        if(opt==1) {
            int x,y,k;
            read(x);read(y);read(k);
            IntervalMul(1,x,y,k);
        }
        if(opt==2) {
            int x,y,k;
            read(x);read(y);read(k);
            IntervalAdd(1,x,y,k);
        }
        if(opt==3) {
            int x,y;
            read(x);read(y);
            ll ans=IntervalSum(1,x,y);
            printf("%lld\n",ans);
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/Apocrypha/p/9432790.html

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值