1. 程式人生 > >hdu-5475 An easy problem---線段樹+取模

hdu-5475 An easy problem---線段樹+取模

每一個 fin const lag update 結果 void 區間 hdu

題目鏈接:

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:\n", ++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\n", tree[1].num); 79 } 80 } 81 return 0; 82 }

hdu-5475 An easy problem---線段樹+取模