zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    XML错误信息Referenced file contains errors (http://www.springframework.org/schema/beans/spring-beans-4.0.xsd). For more information, right click on the message in the Problems View ...
    Description Resource Path Location Type Cannot change version of project facet Dynamic Web Module to 2.3.
    maven创建web报错Cannot read lifecycle mapping metadata for artifact org.apache.maven.plugins:maven-compiler-plugin:maven-compiler-plugin:3.5.1:runtime Cause: error in opening zip file
    AJAX跨域
    JavaWeb学习总结(转载)
    JDBC学习笔记
    Java动态代理之JDK实现和CGlib实现
    (转)看懂UML类图
    spring boot配置使用fastjson
    python3下django连接mysql数据库
  • 原文地址:https://www.cnblogs.com/-Ackerman/p/11456072.html
Copyright © 2011-2022 走看看