NOJ/HUST 1095 校赛 Just Go 线段树模板题
Description
There is a river, which contains n stones from left to right. These stones are magic, each
one has a magic number Ai which means if you stand on the ith stone, you can jump to (i +1)th stone, (i+2)th stone, ..., (i+Ai)th stone(when i+Ai > n, you can only reach as far as n), you want to calculate the number of ways to reach the nth stone.
Notice: you can not jump from right to left!
Input
Input starts with an integer T(1 <= T <= 10), denoting the number of test cases. Each test case contains an integer n(1 <= n <= 105), denoting the number stones. Next line contains n integers Ai(1 <= Ai <= 108).
Output
For each test case, print the number of way to reach the nth stone module 109+7.
Sample Input
3
5
1 2 3 4 5
1
10
2
2 1
Sample Output
3 1 1
题意:给你n个数,对于ai表示可以跳到i+1,i+2,i+3 …i + ai的位置,问到达最后一个位置有几种方法。
思路:第一次接触线段树。由于转移的关系,刚开始想使用DP,但是需要转移的数是一个区间,后来想到因为修改的是一个区间的值,想到用树状数组,但是区间修改的操作好像很烦阿
最终被告知是线段树。
1 #include <stdio.h> 2 #include <iostream> 3 #include <algorithm> 4 #include <string.h> 5 #define nods(x) tree[x] 6 #define lefs(x) tree[x << 1] 7 #define rigs(x) tree[x << 1 | 1] 8 using namespace std; 9 10 const int INF = 0x3f3f3f3f; 11 const int MAX = 100010; 12 const int MOD = 1e9 + 7; 13 14 struct segtree 15 { 16 int l, r, ans; //区间范围 17 int add; //懒惰标记 18 }tree[MAX << 2]; 19 20 //单点修改 21 void change(int &bep, int val) 22 { 23 bep += val; 24 bep = (bep % MOD + MOD) % MOD; 25 } 26 //父节点更新 27 void pushup(int pos) 28 { 29 change(nods(pos).ans, lefs(pos).ans + rigs(pos).ans); 30 } 31 //构造线段树 32 void build(int p, int l, int r) 33 { 34 nods(p).l = l; 35 nods(p).r = r; 36 nods(p).ans = nods(p).add = 0; 37 if(l == r && l == 1) 38 nods(p).ans = 1; 39 if(l == r) 40 return ; 41 42 int mid = (l + r) >> 1; 43 build( p << 1, l, mid ); 44 build( p << 1 | 1, mid + 1, r); 45 pushup(p); 46 } 47 //向下更新叶 通过延迟标记更新 48 void pushdown(int p) 49 { 50 if(nods(p).add) 51 { 52 change(lefs(p).add, nods(p).add); 53 change(rigs(p).add, nods(p).add); 54 change(lefs(p).ans, nods(p).add); 55 change(rigs(p).ans, nods(p).add); 56 nods(p).add = 0; 57 } 58 } 59 //询问 60 int query(int p, int bor) 61 { 62 if(nods(p).l == nods(p).r)//递归到最小叶,直接返回 63 return nods(p).ans; 64 pushdown(p); //先应用标记 再查询 65 66 int mid = (nods(p).l + nods(p).r) >> 1; 67 if(bor <= mid) 68 return query(p << 1, bor); //查询下一层左儿子 69 else return query(p << 1 | 1, bor); //查询下一层右儿子 70 } 71 //区间修改 72 void update(int p, int l, int r, int val) 73 { 74 if(nods(p).l >= l && nods(p).r <= r) //完全包含 75 { 76 change(nods(p).add, val); //延迟标记 77 change(nods(p).ans, val); //更新该点 78 return ; 79 } 80 pushdown(p); //向下更新 81 int mid = (nods(p).l + nods(p).r) >> 1; 82 if(r <= mid) //[l,r] 被包含于 [pl,mid] 83 update(p << 1, l, r , val); 84 else if(l > mid) //[l,r] 被包含于 [mid,pr] 85 update(p << 1 | 1, l, r, val); 86 else //中间截断 87 { 88 update(p << 1, l, mid, val); 89 update(p << 1 | 1,1 + mid, r, val); 90 } 91 pushup(p); 92 } 93 94 95 int main() 96 { 97 int T, t; 98 int ans, ss, ee, n; 99 cin >> T; 100 while(T--) 101 { 102 scanf("%d", &n); 103 build(1, 1, n); 104 for(int i = 1; i <= n; i++) 105 { 106 scanf("%d", &t); 107 ss = i + 1; 108 ee = min(i+t, n); 109 ans = query(1, i); 110 if(i!=n) 111 update(1, ss, ee, ans); 112 } 113 printf("%d\n", query(1, n)); 114 } 115 }