1. 程式人生 > >P3373 【模板】線段樹 2

P3373 【模板】線段樹 2

code onclick 數據 限制 pda src style 復制 fread

P3373 【模板】線段樹 2

題目描述

如題,已知一個數列,你需要進行下面三種操作:

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)

分析

線段樹維護兩個標記,add,mul表示要加的數,和要乘的數。

下傳標記時,add也是要乘以mul的。

還有要開longlong qaq

code

技術分享圖片
 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<vector>
 4 #define lson l,m,rt<<1
 5 #define rson m+1,r,rt<<1|1
 6 #define LL long long
 7 
 8 using namespace std;
 9 const
int N = 500100; 10 LL sum[N],mul[N],add[N]; 11 LL n,m,p; 12 13 inline char nc() { 14 static char buf[100000],*p1,*p2; 15 return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; 16 } 17 inline LL read() { 18 LL x = 0,f = 1;char ch = nc(); 19 for (; ch<0||ch>9; ch = nc()) if (ch==-) f=-1; 20 for (; ch>=0&&ch<=9; ch = nc()) x = x*10+ch-0; 21 return x * f; 22 } 23 void pushup(int rt) { 24 sum[rt] = (sum[rt<<1] + sum[rt<<1|1]) % p; 25 } 26 void pushdown(int rt,int k) { 27 sum[rt<<1] = (sum[rt<<1]*mul[rt]+add[rt]*(k-k/2))%p; 28 sum[rt<<1|1] = (sum[rt<<1|1]*mul[rt]+add[rt]*(k/2))%p; 29 mul[rt<<1] = (mul[rt<<1]*mul[rt])%p; 30 mul[rt<<1|1] = (mul[rt<<1|1]*mul[rt])%p; 31 add[rt<<1] = (add[rt<<1]*mul[rt]+add[rt])%p; 32 add[rt<<1|1] = (add[rt<<1|1]*mul[rt]+add[rt])%p; 33 mul[rt] = 1;add[rt] = 0; 34 } 35 void build(int l,int r,int rt) { 36 mul[rt] = 1,add[rt] = 0; 37 if (l==r) { 38 sum[rt] = read();return ; 39 } 40 int m = (l + r) / 2; 41 build(lson); 42 build(rson); 43 pushup(rt); 44 } 45 void update(int l,int r,int rt,int L,int R,int x,int tp) { 46 if (L <= l && r <= R) { 47 if (tp==0) add[rt] = (add[rt]+x)%p,sum[rt] = (sum[rt]+(r-l+1)*x)%p; 48 else mul[rt]=(mul[rt]*x)%p,add[rt]=(add[rt]*x)%p,sum[rt]=(sum[rt]*x)%p; 49 return ; 50 } 51 pushdown(rt,r-l+1); 52 int m = (l + r) / 2; 53 if (L <= m) update(lson,L,R,x,tp); 54 if (R > m) update(rson,L,R,x,tp); 55 pushup(rt); 56 } 57 LL query(int l,int r,int rt,int L,int R) { 58 if (L <= l && r <= R) { 59 return sum[rt] % p; 60 } 61 pushdown(rt,r-l+1); 62 int m = (l + r) / 2; 63 LL ret = 0; 64 if (L <= m) ret = (ret + query(lson,L,R)) % p; 65 if (R > m) ret = (ret + query(rson,L,R)) % p; 66 return ret % p; 67 } 68 int main () { 69 n = read(),m = read(),p = read(); 70 build(1,n,1); 71 while (m--) { 72 int opt = read(); 73 if (opt==1) { 74 int a = read(),b = read(),c = read(); 75 update(1,n,1,a,b,c,1); 76 } else if (opt==2) { 77 int a = read(),b = read(),c = read(); 78 update(1,n,1,a,b,c,0); 79 } else { 80 int a = read(),b = read(); 81 printf("%lld\n",(query(1,n,1,a,b) + p)%p); 82 } 83 } 84 return 0; 85 }
View Code

P3373 【模板】線段樹 2