码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2019-02-02 23:05:24      阅读:156      评论:0      收藏:0      [点我收藏+]

标签:etc   函数   ||   也会   c++   get   变量   add   tle   

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\n",ask(1,x,y));
122         }
123     }
124     return 0;
125 }

 

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

标签:etc   函数   ||   也会   c++   get   变量   add   tle   

原文地址:https://www.cnblogs.com/c-come/p/10349285.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!