洛谷 P3373 【模板】线段树 2 如题(区间加法+区间乘法+区间求和)

P3373 【模板】线段树 2

  • 时空限制1s / 128MB

题目描述

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

1.将某区间每一个数加上x

2.将某区间每一个数乘上x

3.求出某区间每一个数的和

输入输出格式

输入格式:

 

第一行包含三个整数N、M、P,分别表示该数列数字的个数、操作的总个数和模数。

第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。

接下来M行每行包含3或4个整数,表示一个操作,具体如下:

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

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

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

 

输出格式:

 

输出包含若干行整数,即为所有操作3的结果。

 

输入输出样例

输入样例#1:
5 5 38
1 5 4 2 3
2 1 4 1
3 2 5
1 2 4 2
2 3 5 5
3 1 4
输出样例#1:
17
2

说明

时空限制:1000ms,128M

数据规模:

对于30%的数据:N<=8,M<=10

对于70%的数据:N<=1000,M<=10000

对于100%的数据:N<=100000,M<=100000

(数据已经过加强^_^)

样例说明:

 

故输出应为17、2(40 mod 38=2)

--------------------------------------------------------------------------------------------------------

注意几个点:

       (1)、乘法标记初始化为1;

       (2)、在下传的时候先乘后加;

       (3)、乘法下传里有几个操作:mult*mult、mult*sum、mult*tag、最后别忘了mult=1。

 

还是存个板子:

 

 1 #include<stdio.h>
 2 #include<string.h>
 3 #define maxn 100010
 4 struct node{
 5     int l,r;
 6     long long sum,tag,mult;
 7 };
 8 node tr[maxn*4];
 9 bool flag;
10 int n,m,a[maxn],p;
11 long long read();
12 long long find(int,int,int);
13 void pushup(int);
14 void pushdownsum(int);
15 void pushdownmult(int);
16 void add(int,int,int,int);
17 void build(int,int,int);
18 int main(){
19     n=read();m=read();p=read();
20     for(int i=1;i<=n;i++) a[i]=read();
21     build(1,n,1);
22     for(int i=1;i<=m;i++){
23         int o=read();
24         if(o==1){
25             int x=read(),y=read(),k=read();flag=true;
26             add(x,y,k,1);
27         }
28         else if(o==2){
29             int x=read(),y=read(),k=read();flag=false;
30             add(x,y,k,1);
31         }
32         else{
33             int x=read(),y=read();
34             printf("%lld\n",find(x,y,1));
35         }
36     }
37     return 0;
38 }
39 #define lson o<<1
40 #define rson o<<1|1
41 long long find(int l,int r,int o){
42     if(l<=tr[o].l&&tr[o].r<=r) return tr[o].sum;
43     if(tr[o].mult!=1) pushdownmult(o);
44     if(tr[o].tag) pushdownsum(o);
45     int mid=(tr[o].l+tr[o].r)>>1;
46     if(l<=mid&&r>mid) return (find(l,r,lson)+find(l,r,rson))%p;
47     if(l<=mid)        return find(l,r,lson);
48     if(r>mid)         return find(l,r,rson);
49 }
50 void pushup(int o){
51     tr[o].sum=(tr[lson].sum+tr[rson].sum)%p;
52 }
53 void pushdownmult(int o){
54     long long k=tr[o].mult;tr[o].mult=1;
55     tr[lson].mult=(tr[lson].mult*k)%p;tr[rson].mult=(tr[rson].mult*k)%p;
56     tr[lson].sum=(tr[lson].sum*k)%p;tr[rson].sum=(tr[rson].sum*k)%p;
57     tr[lson].tag=(tr[lson].tag*k)%p;tr[rson].tag=(tr[rson].tag*k)%p;
58 }
59 void pushdownsum(int o){
60     long long k=tr[o].tag;tr[o].tag=0;
61     tr[lson].tag=(tr[lson].tag+k)%p;tr[rson].tag=(tr[rson].tag+k)%p;
62     tr[lson].sum=(tr[lson].sum+k*(tr[lson].r-tr[lson].l+1))%p;
63     tr[rson].sum=(tr[rson].sum+k*(tr[rson].r-tr[rson].l+1))%p;
64 }
65 void add(int l,int r,int k,int o){
66     if(l<=tr[o].l&&tr[o].r<=r){
67         if(flag){
68             tr[o].sum=(tr[o].sum*k)%p;
69             tr[o].mult=(tr[o].mult*k)%p;
70             tr[o].tag=(tr[o].tag*k)%p;
71         }
72         else{
73             tr[o].sum=(tr[o].sum+(tr[o].r-tr[o].l+1)*k)%p;
74             tr[o].tag=(tr[o].tag+k)%p;
75         }
76         return;
77     }
78     if(tr[o].mult!=1) pushdownmult(o);
79     if(tr[o].tag) pushdownsum(o);
80     int mid=(tr[o].l+tr[o].r)>>1;
81     if(l<=mid) add(l,r,k,lson);
82     if(r>mid)  add(l,r,k,rson);
83     pushup(o);
84 }
85 void build(int l,int r,int o){
86     tr[o].l=l;tr[o].r=r;tr[o].mult=1;
87     if(l==r){
88         tr[o].sum=a[l];
89         return;
90     }
91     int mid=(l+r)>>1;
92     build(l,mid,lson);build(mid+1,r,rson);
93     pushup(o);
94 }
95 long long read(){
96     long long ans=0,f=1;char c=getchar();
97     while('0'>c||c>'9'){if(c=='-')f=-1;c=getchar();}
98     while('0'<=c&&c<='9')ans=ans*10+c-48,c=getchar();return ans*f;
99 }
线段树区间乘求和

 

posted @ 2017-11-05 21:21  lpl_bys  阅读(766)  评论(0编辑  收藏  举报