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
", query(1, n));
114     }
115 }


原文地址:https://www.cnblogs.com/Yumesenya/p/5500780.html