题解 P3373 【【模板】线段树 2】


好耶,花了将近一上午,且在\(Quick\)_\(AK\)的帮助在a了这道模板题

简要思路

这道模板题有两个区间操作

  • 将某区间每一个数乘上 x
  • 将某区间每一个数加上 x

有两种操作,那岂不是要两个\(tag\)?

(⊙v⊙)嗯,是的

举个栗子:

假设我们维护一个量\(a\),它有两个标记\(+b\)\(*c\)

因为线段树可以维护支持结合律的数据...(省略一万个字),所以我们要先乘后加

谔谔,都说了是简要思路

#include 
#include 
#include 
#include 
#define ls p<<1
#define int long long
#define rs p<<1|1
using namespace std;
int n,m,a[4000005],dat[4000005],lazy1[4000005];
int lazy2[4000005];
int pp;
int q;
inline int read(){
  int x=0;int f=1;char ch=getchar();
  while(ch>'9'||ch<'0'){if(ch=='-') f=-1;ch=getchar();}
  while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
  return x*f;
}
inline void down(int p,int l,int r){
  int mid=l+r>>1;
  dat[ls]*=lazy1[p],dat[rs]*=lazy1[p];
  dat[ls]%=pp,dat[rs]%=pp;
  dat[ls]+=lazy2[p]*(mid-l+1),dat[rs]+=lazy2[p]*(r-mid);
  dat[ls]%=pp,dat[rs]%=pp;
  lazy1[ls]*=lazy1[p],lazy1[rs]*=lazy1[p];
  lazy1[ls]%=pp,lazy1[rs]%=pp;
  lazy2[ls]*=lazy1[p],lazy2[rs]*=lazy1[p];
  lazy2[ls]%=pp,lazy2[rs]%=pp;
  lazy2[ls]+=lazy2[p],lazy2[rs]+=lazy2[p];
  lazy2[ls]%=pp,lazy2[rs]%=pp;
  lazy1[p]=1;
  lazy2[p]=0;
}
inline void build(int p,int l,int r){
  lazy1[p]=1;
  if(l==r) {dat[p]=a[l];return;}
  int mid=(l+r)>>1;
  build(ls,l,mid);
  build(rs,mid+1,r);
  dat[p]=(dat[ls]+dat[rs])%pp;
}
inline void update1(int p,int x,int y,int l,int r,int k){
  if(x<=l&&y>=r){
    dat[p]*=k;
    dat[p]%=pp;
    lazy1[p]*=k;
    lazy1[p]%=pp;
    lazy2[p]*=k;
    lazy2[p]%=pp;
    return;
  }
  down(p,l,r);
  int mid=l+r>>1;
  if(x<=mid) update1(ls,x,y,l,mid,k);
  if(y>mid) update1(rs,x,y,mid+1,r,k);
  dat[p]=(dat[ls]+dat[rs])%pp;
}
inline void update2(int p,int x,int y,int l,int r,int k){
  if(x<=l&&y>=r){
    dat[p]+=k*(r-l+1);
    dat[p]%=pp;
    lazy2[p]+=k;
    lazy2[p]%=pp;
    return;
  }
  down(p,l,r);
  int mid=l+r>>1;
  if(x<=mid) update2(ls,x,y,l,mid,k);
  if(y>mid) update2(rs,x,y,mid+1,r,k);
  dat[p]=(dat[ls]+dat[rs])%pp;
}
inline int query(int p,int x,int y,int l,int r){
  int res=0;
  if(x<=l&&y>=r) return dat[p]%pp;
  int mid=l+r>>1;
  down(p,l,r);
  if(x<=mid) (res+=query(ls,x,y,l,mid))%pp;
  if(y>mid) (res+=query(rs,x,y,mid+1,r))%pp;
  return res%pp;
}
signed main(){
  n=read();m=read();pp=read();
  for(int i=1;i<=n;i++)
    a[i]=read();
  build(1,1,n);
  for(int i=1;i<=m;i++){
    int c,x,k,y;
    c=read();
    if(c==1){
    x=read();y=read();k=read();
    update1(1,x,y,1,n,k);
    }
    if(c==2){
      x=read();y=read();k=read();
      update2(1,x,y,1,n,k);
    }
    if(c==3){
      x=read();y=read();
      cout<

Luogu P3373 【模板】线段树 2

与此同时,给大家推荐一下双倍经验:
P2023 [AHOI2009] 维护序列

相关