线段树的基础使用+(洛谷3373 )

题目描述

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

1.将某区间每一个数加上x

2.将某区间每一个数乘上x

3.求出某区间每一个数的和

输入输出格式

输入格式:

第一行包含三个整数N、M、P,分别表示该数列数字的个数、操作的总个数和模数。

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

接下来M行每行包含3或4个整数,表示一个操作,具体如下:

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

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

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

输出格式:

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

输入样例#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
按照题目模拟即可,写乘法运算的时候请记得注意以下的小细节:
1.乘法的数组的初始值要设为1,不然系统默认为0做乘法的时候是没有意义的~
2.要注意位运算的使用,在别代码中,二进制的迅速是无法替代的
3.加法和乘法的运算顺序要把握好,乘在先,加在后
4.PushDown函数的加法和乘法需要写在一起,不然前者会把后者的覆盖住,这样就会对后面的产生干扰
5.养成好习惯,做一步,取模一步
前车之鉴,后车之师,下面放上代码,当当当~~(在这里感谢大佬封癫(U25815 )以及 yql的信徒的热切帮助~)

  1 #include<bits/stdc++.h>
  2 #define maxn 1000007
  3 #define LL long long
  4 using namespace std;
  5 LL n,m;
  6 LL c[4*maxn];
  7 LL add[maxn];
  8 LL P;
  9 LL addplus[maxn];
 10 void PushUp(LL rt)
 11 {
 12      c[rt]=c[rt<<1]+c[rt<<1|1];
 13      c[rt]%=P;
 14 }
 15 void Build(LL l,LL r,LL rt)
 16 {
 17      if(l==r)
 18      {
 19          int num;
 20          cin>>num;
 21          c[rt]=num;
 22          return ;
 23      }
 24      addplus[rt]=1;
 25      
 26      LL m=(l+r)>>1;
 27      Build(l,m,rt<<1);
 28      Build(m+1,r,rt<<1|1);
 29      PushUp(rt);
 30 }
 31 void Pushdown(LL rt,LL ln,LL rn)
 32 {
 33    if((addplus[rt]==1)&&(!add[rt]))return ;//这里要用"&&",如果满足一种情况也是要进行考虑的 
 34    
 35        addplus[rt<<1]=(addplus[rt<<1]*addplus[rt])%P;
 36        addplus[rt<<1|1]=(addplus[rt<<1|1]*addplus[rt])%P;
 37        c[rt<<1]=(c[rt<<1]*addplus[rt])%P;
 38        c[rt<<1|1]=(c[rt<<1|1]*addplus[rt])%P;
 39        
 40       add[rt<<1]=(add[rt<<1]*addplus[rt]+add[rt])%P;
 41       add[rt<<1|1]=(add[rt<<1|1]*addplus[rt]+add[rt])%P;
 42       c[rt<<1]=(c[rt<<1]+add[rt]*ln)%P;
 43       c[rt<<1|1]=(c[rt<<1|1]+add[rt]*rn)%P;
 44       
 45       add[rt]=0;
 46       addplus[rt]=1;
 47 }
 48 void Update_interval(LL L,LL R,LL C,LL l,LL r,LL  rt)
 49 {
 50     if(L<=l&&r<=R)
 51     {
 52       c[rt]+=C*(r-l+1);
 53       c[rt]%=P;
 54       add[rt]+=C;
 55       add[rt]%=P;
 56       return ;
 57    }
 58    LL m=(l+r)>>1;
 59    Pushdown(rt,m-l+1,r-m);
 60    if(L<=m) Update_interval(L,R,C,l,m,rt<<1);
 61    if(R>m) Update_interval(L,R,C,m+1,r,rt<<1|1);
 62    PushUp(rt);
 63    return ;
 64 }
 65 LL Query(LL L,LL R,LL l,LL r,LL rt)
 66 {
 67        if(L<=l&&r<=R)
 68           return c[rt];
 69       LL m=(l+r)>>1;
 70       LL ans=0;
 71       Pushdown(rt,m-l+1,r-m);
 72       if(L<=m) ans+=Query(L,R,l,m,rt<<1);
 73       if(R>m) ans+=Query(L,R,m+1,r,rt<<1|1);
 74       PushUp(rt);
 75       ans%=P;
 76       return ans;
 77 }
 78 void Update_intervalplus(LL L,LL R,LL C,LL l,LL r,LL rt)
 79 {
 80    if(L<=l&&r<=R)
 81     {
 82       c[rt]*=C;
 83       c[rt]%=P;
 84       add[rt]*=C;
 85       add[rt]%=P;
 86       addplus[rt]*=C;
 87       addplus[rt]%=P;
 88       return ;
 89    }
 90    LL m=(l+r)>>1;
 91    Pushdown(rt,m-l+1,r-m);
 92    if(L<=m) Update_intervalplus(L,R,C,l,m,rt<<1);
 93    if(R>m) Update_intervalplus(L,R,C,m+1,r,rt<<1|1);
 94    PushUp(rt);
 95    return ;
 96 }
 97 
 98 int main()
 99 {
100     ios::sync_with_stdio(false);//这句话一定要加上,不然c++的输入输出太慢了。 
101     cin>>n>>m;
102     cin>>P;
103       Build(1,n,1);
104       LL t1,t2,t3,t4;
105     for(LL  i=1;i<=m;i++)
106     {
107          cin>>t1;
108          if(t1==1)
109          {
110             cin>>t2>>t3>>t4;
111             Update_intervalplus(t2,t3,t4,1,n,1);
112          }
113          if(t1==2)
114           { 
115                   cin>>t2>>t3>>t4;
116                   Update_interval(t2,t3,t4,1,n,1);
117           }
118           if(t1==3)
119           {
120              cin>>t2>>t3;
121              cout<<(Query(t2,t3,1,n,1))%P<<endl;
122           }
123     }  
124     return 0;
125 }

 

 





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值