题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5475
题目大意:
给X赋初值1,然后给Q个操作,每个操作对应一个整数M;
如果操作是1则将X乘以对应的M,
如果是2则除以第M次操作对应的M',求每次操作后X的值对给定值取摸的结果。
解题思路:
第一眼看这道题,以为就是水题,直接模拟暴力呀,但是发现这样是错误的,因为这里有除法,对除法取模,就应该是逆元,但是逆元不一定存在
想了之后发现可以用线段树保存每一个要乘以的数字,对于操作一就加入数字即可,操作二就对第M次操作的数字进行标记,不让他参与乘法运算,每次输出tree[1]的值就可以了。
线段树维护两个值,一个为标记,一个是区间内的数字的积,对于操作一,更新叶节点,并且更新其父节点。对于操作2也是更新叶节点,标记他,更新父节点时,不让标记过的叶节点参与乘法运算。
1 #include<bits/stdc++.h> 2 #define MID(l, r) (l + (r - l) / 2) 3 #define lc (o<<1) 4 #define rc (o<<1|1) 5 using namespace std; 6 typedef long long ll; 7 int n, m; 8 const int maxn = 100000 + 10; 9 struct node 10 { 11 bool flag; 12 ll num; 13 int l, r; 14 }tree[maxn << 2]; 15 void build(int o,int l, int r) 16 { 17 tree[o].l = l, tree[o].r = r; 18 tree[o].flag = 1; 19 if(l == r) 20 { 21 tree[o].num = 1; 22 return; 23 } 24 int m = MID(l ,r); 25 build(lc, l, m); 26 build(rc, m + 1, r); 27 tree[o].num = 1; 28 if(tree[lc].flag)tree[o].num = tree[o].num * tree[lc].num % m; 29 if(tree[rc].flag)tree[o].num = tree[o].num * tree[rc].num % m; 30 } 31 int flag; 32 int p, v; 33 void update(int o) 34 { 35 if(tree[o].l == tree[o].r) 36 { 37 if(flag) 38 { 39 tree[o].flag = 1; 40 tree[o].num = v; 41 } 42 else 43 { 44 tree[o].flag = 0; 45 } 46 return; 47 } 48 if(p <= tree[lc].r)update(lc); 49 else update(rc); 50 tree[o].num = 1; 51 if(tree[lc].flag)tree[o].num = tree[o].num * tree[lc].num % m; 52 if(tree[rc].flag)tree[o].num = tree[o].num * tree[rc].num % m; 53 } 54 int main() 55 { 56 int T, cases = 0; 57 cin >> T; 58 while(T--) 59 { 60 printf("Case #%d: ", ++cases); 61 scanf("%d%d", &n, &m); 62 int a, b; 63 build(1, 1, n); 64 for(int i = 1; i <= n; i++) 65 { 66 scanf("%d%d", &a, &b); 67 if(a == 1) 68 { 69 flag = 1; 70 p = i, v = b; 71 } 72 else 73 { 74 flag = 0; 75 p = b; 76 } 77 update(1); 78 printf("%lld ", tree[1].num); 79 } 80 } 81 return 0; 82 }