[TJOI2018]数学计算 线段树
题解:
,,,考场上看到这题,没想到竟然是省选原题QAQ,考场上把它当数学题想了好久,因为不知道怎么处理有些数没有逆元的问题。。。。知道这是线段树后恍然大悟。
首先可以一开始就建出一个长度为n的操作序列,初始值都是1,表示一开始默认是1乘上n个1,因为乘1也就相当于没乘。
对于操作1,直接将操作序列上对应的位置单点修改为给定值,维护区间乘积。
对于操作2,将序列上对应位置单点修改为1.
查询直接查询线段树的根即可。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define R register int 4 #define AC 401000 5 #define LL long long 6 7 int n, p, w, go, T; 8 int l[AC], r[AC]; 9 LL tree[AC]; 10 11 inline int read() 12 { 13 int x = 0;char c = getchar(); 14 while(c > '9' || c < '0') c = getchar(); 15 while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); 16 return x; 17 } 18 19 void pre() 20 { 21 n = read(), p = read(); 22 } 23 24 void update(int x) 25 { 26 tree[x] = tree[x * 2] * tree[x * 2 + 1] % p; 27 } 28 29 void build(int x, int ll, int rr) 30 { 31 l[x] = ll, r[x] = rr; 32 if(ll == rr) 33 { 34 tree[x] = 1; 35 return; 36 } 37 int mid = (ll + rr) >> 1; 38 build(x * 2, ll, mid); 39 build(x * 2 + 1, mid + 1, rr); 40 update(x); 41 } 42 43 void change(int x) 44 { 45 if(l[x] == r[x]) 46 { 47 tree[x] = w; 48 return ; 49 } 50 int mid = (l[x] + r[x]) >> 1; 51 if(go <= mid) change(x * 2); 52 else change(x * 2 + 1); 53 update(x); 54 } 55 56 void work() 57 { 58 T = read(); 59 while(T--) 60 { 61 pre(); 62 build(1, 1, n); 63 int opt; 64 for(R i = 1; i <= n; i ++) 65 { 66 opt = read(); 67 if(opt == 1) 68 { 69 w = read() % p, go = i; 70 change(1); 71 } 72 else 73 { 74 w = 1, go = read(); 75 change(1); 76 } 77 printf("%lld\n", tree[1]); 78 } 79 } 80 } 81 82 int main() 83 { 84 freopen("in.in", "r", stdin); 85 work(); 86 fclose(stdin); 87 return 0; 88 }