• 【P3373】 【模板】线段树 2 {线段树,模板}


    OMG_Data_Structure So_Interesting_Mother-Fucker(译:数据结构,奥妙重重)

    虽然只是模板,但还是挺麻烦的,可见数据结构都是毒瘤

    已知一个数列,你需要进行下面三种操作:

    操作1: 格式:1 x y k 含义:将区间[x,y]内每个数乘上k

    操作2: 格式:2 x y k 含义:将区间[x,y]内每个数加上k

    操作3: 格式:3 x y 含义:输出区间[x,y]内每个数的和对P取模所得的结果

    首先一定要用lazy标记,不然妥妥TLE。

    这道题比最基本的模板多了乘法和取模,但加法和乘法这两个玩意和取模是很友好的,所以很简单。

    通过思考加法和乘法的运算律,可以写出如下代码。

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <algorithm>
      4 #define repo(i,a,b) for(int i = a;i <= b;++i)
      5 #define repi(i,a,b) for(int i = a;i >= b;++i)
      6 using namespace std;
      7 
      8 struct segment_tree{
      9     int l,r;
     10     long long sum,add,mul;//sum为区间和,add为加法懒惰标记,mul为乘法懒惰标记 
     11     #define l(x) tree[x].l
     12     #define r(x) tree[x].r
     13     #define sum(x) tree[x].sum
     14     #define add(x) tree[x].add
     15     #define mul(x) tree[x].mul//节省寿命防止眼瞎的宏定义 
     16 } tree[100002*4];
     17 long long a[100002],n,m,mod,oper,x,y,k;//oper表示操作编号 
     18 
     19 inline int read(){//快读 
     20     long long s=0,w=1;
     21     char ch = getchar();
     22     while(ch < '0' || ch > '9'){
     23         if(ch == '-')w = -1;
     24         ch = getchar();
     25     }
     26     while(ch >= '0' && ch <= '9'){
     27         s = s*10+ch-'0';
     28         ch = getchar();
     29     }
     30     return w*s;
     31 }
     32 
     33 inline void build(int p,int l,int r){//建树 
     34     l(p) = l,r(p) = r;
     35     mul(p) = 1;//别忘了初始化mul(p),C++11才支持struct内non_static变量的初始化 
     36     if(l==r){sum(p) = a[l] % mod;return;}
     37     int mid = (l+r)/2;
     38     build(p*2,l,mid);
     39     build(p*2+1,mid+1,r);
     40     sum(p) = (sum(p*2) + sum(p*2+1)) % mod;
     41 }
     42 
     43 inline int len(int p){//节省寿命防止眼瞎的函数 
     44     return r(p)-l(p)+1;
     45 }
     46 
     47 inline void spread(int p){
     48     if(add(p) || mul(p)!=1){//如果有标记要传的话 
     49         sum(p*2) = sum(p*2)*mul(p) % mod;
     50         sum(p*2+1) = sum(p*2+1)*mul(p) % mod;
     51         mul(p*2) = mul(p*2)*mul(p) % mod;
     52         mul(p*2+1) = mul(p*2+1)*mul(p) % mod;
     53         add(p*2) = add(p*2)*mul(p) % mod;
     54         add(p*2+1) = add(p*2+1)*mul(p) % mod;//子树的add也会受到乘法的影响,即(a+add)*mul 
     55         mul(p) = 1;//mul(p) down
     56         
     57         sum(p*2) = (sum(p*2)+add(p)*len(p*2)) % mod;
     58         sum(p*2+1) = (sum(p*2+1)+add(p)*len(p*2+1)) % mod;
     59         add(p*2) = (add(p*2)+add(p)) % mod;
     60         add(p*2+1) = (add(p*2+1)+add(p)) % mod;
     61         add(p) = 0;//add(p) down
     62     }
     63 }//除了把p*2和p*2+1各自都写出来,还可以写一个devide_spread()函数
     64  //调用devide_spread(p*2),devide_spread(p*2+1)
     65 
     66 inline void oper_add(int p,int l,int r,int d){//加法操作 
     67     if(l <= l(p) && r >= r(p)){
     68         sum(p) = (sum(p)+(long long)d*len(p)) % mod;
     69         add(p) = (add(p)+d) % mod;
     70         return;
     71     }
     72     spread(p);
     73     int mid = (l(p)+r(p))/2;
     74     if(l <= mid)oper_add(p*2,l,r,d);
     75     if(r > mid)oper_add(p*2+1,l,r,d);
     76     sum(p) = (sum(p*2)+sum(p*2+1)) % mod;
     77 }
     78 
     79 inline void oper_mul(int p,int l,int r,int d){//乘法操作 
     80     if(l <= l(p) && r >= r(p)){
     81         sum(p) = (sum(p)*d) % mod;
     82         add(p) = (add(p)*d) % mod;//同spread()函数里的解释 
     83         mul(p) = (mul(p)*d) % mod;
     84         return;
     85     }
     86     spread(p);
     87     int mid = (l(p)+r(p))/2;
     88     if(l <= mid)oper_mul(p*2,l,r,d);
     89     if(r > mid)oper_mul(p*2+1,l,r,d);
     90     sum(p) = (sum(p*2)+sum(p*2+1)) % mod;
     91 }
     92 
     93 inline long long ask(int p,int l,int r){//询问 
     94     if(l <= l(p) && r >= r(p))return sum(p) % mod;
     95     spread(p);
     96     int mid = (l(p)+r(p))/2;
     97     long long val = 0;
     98     if(l <= mid)val = (val+ask(p*2,l,r)) % mod;
     99     if(r > mid)val = (val+ask(p*2+1,l,r)) % mod;
    100     return val;
    101 }
    102 
    103 int main(){
    104     n = read(),m = read(),mod = read();
    105     repo(i,1,n){
    106         a[i] = read();
    107     }
    108     build(1,1,n);
    109     repo(i,1,m){
    110         oper = read();
    111         if(oper == 1){
    112             x = read(),y = read(),k = read();
    113             oper_mul(1,x,y,k);
    114         }
    115         if(oper == 2){
    116             x = read(),y = read(),k = read();
    117             oper_add(1,x,y,k);
    118         }
    119         if(oper == 3){
    120             x = read(),y = read();
    121             printf("%lld
    ",ask(1,x,y));
    122         }
    123     }
    124     return 0;
    125 }
  • 相关阅读:
    静态连接库
    03数据的增删改查
    02MySQL中的数据类型
    01MySQL的 库、表初步认识
    Python 函数
    Linux系统目录结构
    Linux系统启动过程
    第三章 Web页面建设
    《第二章:深入了解超文本》
    《HTML与CSS 第一章 认识HTML》读书笔记
  • 原文地址:https://www.cnblogs.com/c-come/p/10349285.html
Copyright © 2020-2023  润新知