1. 程式人生 > >BZOJ5334:[TJOI2018]數學計算(線段樹)

BZOJ5334:[TJOI2018]數學計算(線段樹)

mem 有一個 urn fin 數學 getchar() sin char get

Description

小豆現在有一個數x,初始值為1. 小豆有Q次操作,操作有兩種類型: 1 m: x = x * m ,輸出 x%mod; 2 pos: x = x / 第pos次操作所乘的數(保證第pos次操作一定為類型1,對於每一個類型1 的操作至多會被除一次),輸出x%mod

Input

一共有t組輸入(t ≤ 5) 對於每一組輸入,第一行是兩個數字Q, mod(Q ≤ 100000, mod ≤ 1000000000); 接下來Q行,每一行為操作類型op,操作編號或所乘的數字m(保證所有的輸入都是合法的). 1 ≤ Q ≤ 100000

Output

對於每一個操作,輸出一行,包含操作執行後的x%mod的值

Sample Input

1
10 1000000000
1 2
2 1
1 2
1 10
2 3
2 4
1 6
1 7
1 12
2 7

Sample Output

2
1
2
20
10
1
6
42
504
84

Solution

一開始以為是個數學題……

後來發現就是以操作序號為下標建線段樹,修改就單點修改,查詢就是查詢線段樹根的乘積。

Code

 1 #include<iostream>
 2 #include<cstring>
 3
#include<cstdio> 4 #define N (100009) 5 using namespace std; 6 7 struct Sgt{int val,ls,rs;}Segt[N*20]; 8 int T,q,MOD,sgt_num,Root,opt,m; 9 10 inline int read() 11 { 12 int x=0,w=1; char c=getchar(); 13 while (c<0 || c>9) {if (c==-) w=-1; c=getchar();} 14 while
(c>=0 && c<=9) x=x*10+c-0, c=getchar(); 15 return x*w; 16 } 17 18 void Pushup(int now) 19 { 20 Segt[now].val=1; 21 int ls=Segt[now].ls,rs=Segt[now].rs; 22 if (ls) Segt[now].val=1ll*Segt[now].val*Segt[ls].val%MOD; 23 if (rs) Segt[now].val=1ll*Segt[now].val*Segt[rs].val%MOD; 24 } 25 26 void Update(int &now,int l,int r,int x,int k) 27 { 28 if (!now) now=++sgt_num; 29 if (l==r) {Segt[now].val=k; return;} 30 int mid=(l+r)>>1; 31 if (x<=mid) Update(Segt[now].ls,l,mid,x,k); 32 else Update(Segt[now].rs,mid+1,r,x,k); 33 Pushup(now); 34 } 35 int main() 36 { 37 T=read(); 38 while (T--) 39 { 40 memset(Segt,0,sizeof(Segt)); 41 sgt_num=0; Root=0; 42 q=read(); MOD=read(); 43 for (int i=1; i<=q; ++i) 44 { 45 opt=read(); m=read(); 46 if (opt==1) Update(Root,1,q,i,m); 47 else Update(Root,1,q,m,1); 48 printf("%d\n",Segt[Root].val); 49 } 50 } 51 }

BZOJ5334:[TJOI2018]數學計算(線段樹)