P3373 【模板】线段树 2 (线段树多重标记入门)

题目链接:https://www.luogu.org/problem/P3373

 

讲讲优先级的问题:

1. 加法和乘法顺序不一样会导致不同的结果

比如: (a+b)c 不等于 ac + b

而在记录懒标记的时候,加法和乘法两种标记放到一起,并不知道哪个先,哪个后。

所以要确定一个优先级

我们分析一下两种顺序:

(1) 先加后乘 : (a+b)c = ac + b*c

(2) 先乘后加:a*c + b

比较一下,发现,上面的先加后乘相当于下面的式子,在加法上面多乘了一个c

所以,我们只要是先加后乘的式子,只要加一个*c就可以转化为先乘后加的式子

具体的操作就是在添加乘法标记的时候,把加法标记*c就好了

所以,我们就定了一个总顺序:先乘后加

然后在标记传递pushdown的时候,儿子的加法标记传递完也要保持先乘后加的顺序

 

举个例子: ac+b 这是儿子原来的懒标记 然后加入C和B是父亲的懒标记,那么按照先乘后加应该这么算:(ac+b)*C+B

            化简: = acC+b*C+B

                  = a(cC) + (b*C+B)

所以,原来的a重叠懒标记后应该是这样的,乘法标记是cC, 加法标记是 bC+B

 

  1 #include <stdio.h>
  2 #include <algorithm>
  3 #include <iostream>
  4 #include <stdbool.h>
  5 #include <stdlib.h>
  6 #include <string>
  7 #include <string.h>
  8 #include <stack>
  9 #include <queue>
 10 #include <set>
 11 #include <map>
 12 #include <math.h>
 13 
 14 #define INF 0x3f3f3f3f
 15 #define LL long long
 16 using namespace std;
 17 
 18 const int maxn = 300100;
 19 LL arr[maxn];
 20 LL p;
 21 
 22 struct segment_tree{
 23     int l,r;
 24     LL val;
 25     LL mul,add;
 26 }tree[maxn*4];
 27 
 28 void pushup(int nod){
 29     tree[nod].val = (tree[nod<<1].val + tree[(nod<<1)+1].val) % p;
 30 }
 31 
 32 void pushdown(int nod){
 33     int l = tree[nod].l,r = tree[nod].r;
 34     int mid = (l + r) >> 1;
 35     // 我们假设的是乘法优先
 36     tree[nod<<1].val = (tree[nod<<1].val*tree[nod].mul + tree[nod].add*(mid-l+1)) % p;
 37     tree[(nod<<1)+1].val = (tree[(nod<<1)+1].val*tree[nod].mul + tree[nod].add*(r-mid)) % p;
 38     // 维护 mul 和 add
 39     tree[nod<<1].mul = (tree[nod<<1].mul*tree[nod].mul) % p;
 40     tree[(nod<<1)+1].mul = (tree[(nod<<1)+1].mul*tree[nod].mul) % p;
 41     tree[nod<<1].add = (tree[nod<<1].add*tree[nod].mul+tree[nod].add) % p;
 42     tree[(nod<<1)+1].add = (tree[(nod<<1)+1].add*tree[nod].mul+tree[nod].add) % p;
 43     // 注意清空
 44     tree[nod].mul = 1;
 45     tree[nod].add = 0;
 46 }
 47 
 48 void build(int l,int r,int nod){
 49     tree[nod].mul = 1;
 50     tree[nod].add = 0;
 51     tree[nod].l = l;
 52     tree[nod].r = r;
 53     if (l == r){
 54         tree[nod].val = arr[l] % p;
 55         return ;
 56     }
 57     int mid = (l + r) >> 1;
 58     build(l,mid,nod<<1);
 59     build(mid+1,r,(nod<<1)+1);
 60     pushup(nod);
 61 }
 62 void updata1(int x,int y,LL k,int nod=1){  // 乘法
 63     int l = tree[nod].l,r = tree[nod].r;
 64     if (x <= l && y >= r){
 65         tree[nod].val = (tree[nod].val * k) % p;
 66         tree[nod].mul = (tree[nod].mul * k) % p;
 67         // 这里就是我们说的在添加乘法标记的时候,把加法标记*c就好了
 68         tree[nod].add = (tree[nod].add * k) % p;
 69         return ;
 70     }
 71     pushdown(nod);
 72     int mid = (l + r) >> 1;
 73     if (x <= mid){
 74         updata1(x,y,k,nod<<1);
 75     }
 76     if (y > mid){
 77         updata1(x,y,k,(nod<<1)+1);
 78     }
 79     pushup(nod);
 80 }
 81 
 82 void updata2(int x,int y,LL k,int nod=1){  // 加法
 83     int l = tree[nod].l,r = tree[nod].r;
 84     if (x <= l && y >= r){
 85         tree[nod].add = (tree[nod].add + k) % p;
 86         tree[nod].val = (tree[nod].val + (r-l+1) * k) % p;
 87         return ;
 88     }
 89     pushdown(nod);
 90     int mid = (l + r) >> 1;
 91     if (x <= mid){
 92         updata2(x,y,k,nod<<1);
 93     }
 94     if (y > mid){
 95         updata2(x,y,k,(nod<<1)+1);
 96     }
 97     pushup(nod);
 98 }
 99 
100 LL query(int x,int y,int nod=1){
101     int l = tree[nod].l,r = tree[nod].r;
102     if (x <= l && y >= r){
103         return tree[nod].val % p;
104     }
105     pushdown(nod);
106     int mid = (l + r) >> 1;
107     LL sum = 0;
108     if (x <= mid){
109         sum += query(x,y,nod<<1);
110     }
111     if (y > mid){
112         sum += query(x,y,(nod<<1)+1);
113     }
114     return sum % p;
115 }
116 
117 int main(){
118     int n,m;
119     scanf("%d%d%lld",&n,&m,&p);
120     for (int i=1;i<=n;i++){
121         scanf("%lld",&arr[i]);
122     }
123     build(1,n,1);
124     while (m--){
125         int op;
126         scanf("%d",&op);
127         int x,y;
128         LL k;
129         if (op == 1){
130             scanf("%d%d%lld",&x,&y,&k);
131             updata1(x,y,k);
132         }
133         else if (op == 2){
134             scanf("%d%d%lld",&x,&y,&k);
135             updata2(x,y,k);
136         }
137         else {
138             scanf("%d%d",&x,&y);
139             printf("%lld\n",query(x,y));
140         }
141     }
142     return 0;
143 }

 

posted @ 2019-09-03 22:14  _Ackerman  阅读(264)  评论(0编辑  收藏  举报