• 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
    ",query(x,y));
    140         }
    141     }
    142     return 0;
    143 }
  • 相关阅读:
    辛星和你彻底搞清CSS中的相对定位和绝对定位
    快速向表中插入大量数据Oracle中append与Nologging
    关于insert /*+ append*/ 各种insert插入速度比较
    dblink连接的目标端 session不断的问题。
    oracle操作记录
    ORACLE快速彻底Kill掉的会话
    Oracle 死锁的检测查询及处理
    Oracle 11g必须开启的服务及服务详细介绍
    oracle job有定时执行的功能,可以在指定的时间点或每天的某个时间点自行执行任务。
    Oracle报 ORA-00054资源正忙的解决办法
  • 原文地址:https://www.cnblogs.com/-Ackerman/p/11456072.html
Copyright © 2020-2023  润新知