BZOJ 2002: [Hnoi2010]Bounce 弹飞绵羊 【分块】
任意门:https://www.lydsy.com/JudgeOnline/problem.php?id=2002
2002: [Hnoi2010]Bounce 弹飞绵羊
Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 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
1 2 1 1
3
1 1
2 1 1
1 1
Sample Output
2
3
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\n", 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 }