线段树-----乘加操作懒惰标记如何下传

第二天叫醒我的不是闹钟,是梦想!

题目描述
如题,已知一个数列,你需要进行下面三种操作:

将某区间每一个数乘上 xx

将某区间每一个数加上 xx

求出某区间每一个数的和

输入格式
第一行包含三个整数 n,m,pn,m,p,分别表示该数列数字的个数、操作的总个数和模数。

第二行包含 nn 个用空格分隔的整数,其中第 ii 个数字表示数列第 ii 项的初始值。

接下来 mm 行每行包含若干个整数,表示一个操作,具体如下:

操作 11: 格式:1 x y k 含义:将区间 [x,y][x,y] 内每个数乘上 kk

操作 22: 格式:2 x y k 含义:将区间 [x,y][x,y] 内每个数加上 kk

操作 33: 格式:3 x y 含义:输出区间 [x,y][x,y] 内每个数的和对 pp 取模所得的结果

输出格式
输出包含若干行整数,即为所有操作 33 的结果。

输入输出样例
输入 #1复制
5 5 38
1 5 4 2 3
2 1 4 1
3 2 5
1 2 4 2
2 3 5 5
3 1 4
输出 #1复制
17
2

//乘法和加法一起的时候,懒惰标记下传的优先级是先乘再加



#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
typedef long long ll;
ll n,m,p;
ll a[N];
struct node
{
  ll l,r,sum,mul,add;  
}tree[N<<4];
void push_up(ll root)
{
  tree[root].sum=(tree[root<<1].sum+tree[root<<1|1].sum)%p;
}

void push_down(int root)
{
    tree[root<<1].sum=(ll)(tree[root].mul*tree[root<<1].sum+((tree[root<<1].r-tree[root<<1].l+1)*tree[root].add)%p)%p;
    tree[root<<1|1].sum=(ll)(tree[root].mul*tree[root<<1|1].sum+((tree[root<<1|1].r-tree[root<<1|1].l+1)*tree[root].add)%p)%p;

    tree[root<<1].mul=(ll)(tree[root<<1].mul*tree[root].mul)%p;
    tree[root<<1|1].mul=(ll)(tree[root<<1|1].mul*tree[root].mul)%p;

    tree[root<<1].add=(ll)(tree[root<<1].add*tree[root].mul+tree[root].add)%p;
    tree[root<<1|1].add=(ll)(tree[root<<1|1].add*tree[root].mul+tree[root].add)%p;


    tree[root].mul=1;
    tree[root].add=0;
}
void build(ll root,ll l,ll r)
{
  tree[root].l=l;tree[root].r=r;tree[root].mul=1;
  if(l==r){
    tree[root].sum=a[l]%p;
    return ;
  }
  ll mid=l+r>>1;
  build(root<<1,l,mid);
  build(root<<1|1,mid+1,r);
  push_up(root);
}
void add(int root,int l,int r,int val)
{
  if(tree[root].l>=l&&tree[root].r<=r){
    tree[root].add=(tree[root].add+val)%p;
    tree[root].sum=(ll)(tree[root].sum+val*(tree[root].r-tree[root].l+1))%p;
    return ;
  }
  push_down(root);
  int mid=(tree[root].l+tree[root].r)>>1;
  if(l<=mid) add(root<<1,l,r,val);
  if(r>mid) add(root<<1|1,l,r,val);
  push_up(root);
}
void mu(int root,int l,int r,int val)
{
  if(tree[root].l>=l&&tree[root].r<=r){
    tree[root].mul=(tree[root].mul*val)%p;
    tree[root].sum=(tree[root].sum*val)%p;
    tree[root].add=(tree[root].add*val)%p;
    return ;
  }
  push_down(root);
  int mid=(tree[root].l+tree[root].r)>>1;
  if(l<=mid ) mu(root<<1,l,r,val);
  if(r>mid) mu(root<<1|1,l,r,val);
  push_up(root);

}
ll query(int root,int l,int r)
{
  ll res=0;
  if(tree[root].l>=l&&tree[root].r<=r) return tree[root].sum;
  int mid=tree[root].l+tree[root].r>>1;
  push_down(root);
  if(l<=mid) res+=query(root<<1,l,r)%p;
  if(r>mid) res+=query(root<<1|1,l,r)%p;
  return res%p;
}
int main()
{
    scanf("%lld %lld %lld",&n,&m,&p);
    int op,x,y,k;
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    build(1,1,n);
  //  cout<<"**********"<<endl;
    for(int i=1;i<=m;i++)
    {
      scanf("%d",&op);
      if(op==1)
      {
        scanf("%d %d %d",&x,&y,&k);
        mu(1,x,y,k);
      }
      else if(op==2)
      {
        scanf("%d %d %d",&x,&y,&k);
        add(1,x,y,k);
      }
      else if(op==3)
      {
        scanf("%d %d",&x,&y);
        cout<<query(1,x,y)<<endl;;
      }
    }

}

发布了289 篇原创文章 · 获赞 6 · 访问量 4011

猜你喜欢

转载自blog.csdn.net/qq_43690454/article/details/103412165