bzoj 1798 维护序列seq

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1798

题解:

  高级一点的线段树,加上了区间乘法运算,则需要增加一个数组mulv记录乘的因数,在下放更新sumv和addv值的都时候要先乘再加

  被蓝书的写法坑了,就一直搞不懂下放和sumv、addv数组的具体用法,导致网上大犇们的程序我基本都看不懂,写完这道题感觉重新学了一遍线段树

 1 #include<cstdio>
 2 #include<cstring>
 3 #define MAXN 400010
 4 #define LL long long
 5 LL MOD,sumv[MAXN],addv[MAXN],mulv[MAXN];
 6 int n,m,t1,y1,y2,v;
 7 void maintain(int o,int len)//下放 
 8 {
 9     int lc=o<<1,rc=(o<<1)+1,M=len>>1;
10     if(mulv[o]!=1||addv[o])
11     {
12         mulv[lc]=(mulv[lc]*mulv[o])%MOD;
13         mulv[rc]=(mulv[rc]*mulv[o])%MOD;
14         addv[lc]=((addv[lc]*mulv[o])+addv[o])%MOD;
15         addv[rc]=((addv[rc]*mulv[o])+addv[o])%MOD;
16         sumv[lc]=(sumv[lc]*mulv[o]+(len-M)*addv[o])%MOD;
17         sumv[rc]=(sumv[rc]*mulv[o]+M*addv[o])%MOD;
18     }
19     addv[o]=0;
20     mulv[o]=1;
21 }
22 void build(int o,int L,int R)
23 {
24     int lc=o<<1,rc=(o<<1)+1,M=(L+R)/2;
25     if(L==R)
26     {
27         scanf("%lld",&sumv[o]);
28         return;
29     }
30     build(lc,L,M);
31     build(rc,M+1,R);
32     sumv[o]=(sumv[lc]+sumv[rc])%MOD;
33 }
34 void update(int o,int L,int R)
35 {
36     int lc=o<<1,rc=(o<<1)+1,M=(L+R)/2;
37     if(y1<=L&&y2>=R)
38     {
39         if(t1==1)
40         {
41             addv[o]=(addv[o]*v)%MOD;
42             sumv[o]=(sumv[o]*v)%MOD;
43             mulv[o]=(mulv[o]*v)%MOD;
44         }
45         else
46         {
47             addv[o]=(addv[o]+v)%MOD;
48             sumv[o]=(sumv[o]+v*(R-L+1))%MOD;
49         }
50         return;
51     }
52     maintain(o,R-L+1);
53     if(y1<=M)update(lc,L,M);
54     if(y2>M)update(rc,M+1,R);
55     sumv[o]=(sumv[lc]+sumv[rc])%MOD;
56 }
57 LL query(int o,int L,int R)
58 {
59     int lc=o<<1,rc=(o<<1)+1,M=(L+R)>>1;
60     if(y1<=L&&y2>=R)return sumv[o]%MOD;
61     maintain(o,R-L+1);
62     LL ans=0;
63     if(y1<=M)ans=(query(lc,L,M))%MOD;
64     if(y2>M)ans+=(query(rc,M+1,R))%MOD;
65     sumv[o]=(sumv[lc]+sumv[rc])%MOD;
66     return ans%MOD;
67 }
68 int main()
69 {
70     scanf("%d%lld",&n,&MOD);
71     for(int i=1;i<=400009;i++)mulv[i]=1;
72     build(1,1,n);
73     scanf("%d",&m);
74     while(m--)
75     {
76         scanf("%d%d%d",&t1,&y1,&y2);
77         if(t1!=3)
78         {
79             scanf("%d",&v);
80             update(1,1,n);
81         }
82         else printf("%lld\n",query(1,1,n));
83     }
84     return 0;
85 }

 

转载于:https://www.cnblogs.com/xqmmcqs/p/5967762.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值