zoukankan      html  css  js  c++  java
  • 洛谷P3373 【模板】线段树2

    这题挺揪心的

    想了半天为什么要先乘法后加法

    原因是这样的:

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

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

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

    所以要确定一个优先级

    我们分析一下两种顺序:

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

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

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

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

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

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

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

    比如:addv[o] 是父亲节点的加法标记, mulv[o] 是父亲节点的乘法标记 sumv[o] 是父亲节点的求和值, ls表示左儿子, rs表示右儿子

    那么        o

            ls           rs

    首先,pushdown 的时候,在算儿子的sumv的时候,ls和rs 的懒标记是不用算的(因为我这里懒标记的定义是:不包含该节点,该节点的儿子加上或乘上的值),所以sumv[ls]和sumv[rs]

    还是照样先加后乘的顺序维护

    然后,懒标记叠加时候,要把顺序考虑进去

    举个例子: a*c+b 这是儿子原来的懒标记

                     然后加入C和B是父亲的懒标记,那么按照先乘后加应该这么算:(a*c+b)*C+B

                                化简:  =   a*c*C+b*C+B

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

    所以,原来的a重叠懒标记后应该是这样的,乘法标记是c*C, 加法标记是 b*C+B

    所以,懒标记叠加的时候应该是 mulv 照样乘父亲的mulv, addv要先乘一下父亲的mulv再加一下父亲的addv,这样才算完

    其他的还是该怎么来就怎么来,这里不细说了

    完整代码:

      1 #include<cstdio>
      2 #include<iostream>
      3 
      4 #define LL long long int 
      5 #define ls o<<1
      6 #define rs o<<1|1
      7 #define M ((L+R)>>1)
      8 
      9 using namespace std;
     10 const int maxn = 100010;
     11 
     12 LL n, m, p;
     13 LL A[maxn], sumv[maxn*4], addv[maxn*4], mulv[maxn*4];
     14 
     15 LL add(LL a,LL b) {//方便取模 
     16     return (a+b)%p;
     17 }
     18 
     19 LL mul(LL a,LL b) {
     20     return (a*b)%p;
     21 }
     22 
     23 inline void build(LL o,LL L,LL R) {
     24     mulv[o] = 1;
     25     if(L == R) sumv[o] = A[L] % p;
     26     else {
     27         build(ls,L,M);
     28         build(rs,M+1,R);
     29         sumv[o] = add(sumv[ls],sumv[rs]);
     30     }
     31 }
     32 
     33 inline void pushdown(LL o,LL L,LL R) {//划重点 
     34     sumv[ls] = mul(sumv[ls],mulv[o]);
     35     sumv[rs] = mul(sumv[rs],mulv[o]);
     36     sumv[ls] = add(sumv[ls],addv[o]*(M-L+1)); 
     37     sumv[rs] = add(sumv[rs],addv[o]*(R-M));
     38     
     39     mulv[ls] = mul(mulv[ls],mulv[o]);
     40     mulv[rs] = mul(mulv[rs],mulv[o]);
     41     addv[ls] = mul(addv[ls],mulv[o]);
     42     addv[rs] = mul(addv[rs],mulv[o]);
     43     addv[ls] = add(addv[ls],addv[o]);
     44     addv[rs] = add(addv[rs],addv[o]);
     45 
     46     addv[o] = 0;
     47     mulv[o] = 1;     
     48 }
     49 
     50 LL ql,qr,qa,qm;
     51 inline void updatea(LL o,LL L,LL R) {
     52     if(ql <= L &&  R <= qr) {
     53         addv[o] = add(addv[o],qa);
     54         sumv[o] = add(sumv[o],qa*(R-L+1));
     55         return;
     56     }
     57     pushdown(o,L,R);
     58     if(ql <= M) updatea(ls,L,M);
     59     if(qr > M) updatea(rs,M+1,R);
     60   sumv[o] = add(sumv[ls], sumv[rs]);
     61 }
     62 
     63 inline void updatem(LL o,LL L,LL R) {
     64   if(ql <= L && R <= qr) {
     65       mulv[o] = mul(mulv[o],qm);
     66       addv[o] = mul(addv[o],qm);//加法标记*c 
     67       sumv[o] = mul(sumv[o],qm);
     68       return;
     69     }    
     70     pushdown(o,L,R);
     71     if(ql <= M) updatem(ls,L,M);
     72     if(qr > M) updatem(rs,M+1,R);
     73     sumv[o] = add(sumv[ls], sumv[rs]);
     74 }
     75 
     76 inline LL query(LL o,LL L,LL R) {
     77     if(ql <= L && R <= qr) return sumv[o];
     78     pushdown(o,L,R);
     79     LL ret = 0;
     80     if(ql <= M) ret = add(ret, query(ls,L,M));
     81     if(qr > M) ret = add(ret, query(rs,M+1,R));
     82     return ret%p;
     83 }
     84 
     85 int main() {
     86     cin >> n >> m >> p;
     87     for(int i = 1;i <= n;i++) scanf("%lld",&A[i]);
     88 
     89     build(1,1,n);
     90 
     91     for(int i = 1,x;i <= m;i++) {
     92         scanf("%d",&x);
     93         if(x == 1) {
     94             scanf("%lld%lld%lld",&ql,&qr,&qm);
     95             updatem(1,1,n);
     96         } else if(x == 2) {
     97             scanf("%lld%lld%lld",&ql,&qr,&qa);
     98             updatea(1,1,n);
     99         } else {
    100             scanf("%lld%lld",&ql,&qr);
    101             printf("%lld
    ", query(1,1,n));
    102         }
    103     }
    104 
    105     return 0;
    106 } 
  • 相关阅读:
    常用工具类
    手机端加载中
    jeecg的各种坑
    资源
    idea 破解后无法启动,我的配置文件搞错了
    eclipse xml 报某某.xsd找不到
    linux上部署svn服务器
    苹果手机微信浏览器无法通过post提交form数据
    %%%
    AtCoder arc060_d
  • 原文地址:https://www.cnblogs.com/frankscode/p/9520472.html
Copyright © 2011-2022 走看看