BZOJ 2002: [Hnoi2010]Bounce 弹飞绵羊 【分块】

任意门:https://www.lydsy.com/JudgeOnline/problem.php?id=2002

2002: [Hnoi2010]Bounce 弹飞绵羊

Time Limit: 10 Sec  Memory Limit: 259 MB
Submit: 14824  Solved: 7515
[Submit][Status][Discuss]

Description

某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹ki步,达到第i+ki个装置,若不存在第i+ki个装置,则绵羊被弹飞。绵羊想知道当它从第i个装置起步时,被弹几次后会被弹飞。为了使得游戏更有趣,Lostmonkey可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。

Input

第一行包含一个整数n,表示地上有n个装置,装置的编号从0到n-1,接下来一行有n个正整数,依次为那n个装置的初始弹力系数。第三行有一个正整数m,接下来m行每行至少有两个数i、j,若i=1,你要输出从j出发被弹几次后被弹飞,若i=2则还会再输入一个正整数k,表示第j个弹力装置的系数被修改成k。对于20%的数据n,m<=10000,对于100%的数据n<=200000,m<=100000

Output

对于每个i=1的情况,你都要输出一个需要的步数,占一行。

Sample Input

4
1 2 1 1
3
1 1
2 1 1
1 1

Sample Output

2
3

题意概括:略

解题思路:

在线的查询,神奇暴力算法分块!

记录每个点跳到下一分块的步数和每个点跳到下一分块的位置

AC code:

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <algorithm>
 4 #include <cmath>
 5 #include <cstring>
 6 #define ll long long int
 7 #define INF 0x3f3f3f3f
 8 using namespace std;
 9 const int MAXN = 2e5+10;
10 inline ll read()
11 {
12     ll x = 0, f = 1; char ch = getchar();
13     while(ch > '9' || ch < '0') {if(ch == '-')f = -1; ch = getchar();}
14     while(ch >= '0' && ch <= '9'){x=x*10+ch-'0'; ch = getchar();}
15     return x*f;
16 }
17 int N, M;
18 int block, cnt; ///分块的大小,分块的数量
19 int pt[MAXN], st[MAXN]; ///记录跳打下一个分块的位置 记录跳到下一个分块的步数
20 int K[MAXN];
21 int belong[MAXN];   ///记录当前的数属于第几个分块
22 int l[MAXN], r[MAXN];  ///记录每个分块的左右边界
23 inline int cal(int x)
24 {
25     int temp = 0;
26     while(1){
27         temp+=st[x];
28         if(!pt[x]) break;  ///飞出去了
29         x = pt[x];         ///跳到下一个点
30     }
31     return temp;
32 }
33 int main()
34 {
35     N = read();
36     block = sqrt(N);
37     for(int i = 1; i <= N; i++){
38         K[i] = read();
39     }
40     if(N%block) cnt = N/block+1;
41     else cnt = N/block;
42 
43     for(int i = 1; i <= cnt; i++){
44         l[i] = (i-1)*block+1;    ///相当于退回前一个的右端点+1
45         r[i] = i*block;
46     }
47     r[cnt] = N;
48 
49     for(int i = 1; i <= N; i++){
50         belong[i] = (i-1)/block+1;
51     }
52 
53     for(int i = N; i > 0; i--){
54         if(i+K[i] > N) st[i] = 1;   ///飞出去了
55         else if(belong[i] == belong[i+K[i]]){    ///还没跳出当前分块
56             st[i] = st[i+K[i]]+1; pt[i] = pt[i+K[i]];
57         }
58         else st[i] = 1, pt[i] = i+K[i]; ///跳到下一个分块
59     }
60     M = read();
61     int x, y, command;
62     for(int i = 1; i <= M; i++){
63         command = read(), x = read();
64         x++;
65         if(command == 1) printf("%d
", cal(x));
66         else{
67             y = read();
68             K[x] = y;
69             for(int i = x; i >= l[belong[x]]; i--)
70                 if(belong[i] == belong[i+K[i]]){    ///还没跳出当前分块
71                     st[i] = st[i+K[i]]+1; pt[i] = pt[i+K[i]];
72                 }
73             else st[i] = 1, pt[i] = i+K[i]; ///跳到下一个分块
74         }
75     }
76     return 0;
77 }
View Code
原文地址:https://www.cnblogs.com/ymzjj/p/9566884.html