[分块] 洛谷 P3203 弹飞绵羊

题目描述

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

输入输出格式

输入格式:

第一行包含一个整数n,表示地上有n个装置,装置的编号从0到n-1。

接下来一行有n个正整数,依次为那n个装置的初始弹力系数。

第三行有一个正整数m,

接下来m行每行至少有两个数i、j,若i=1,你要输出从j出发被弹几次后被弹飞,若i=2则还会再输入一个正整数k,表示第j个弹力装置的系数被修改成k。

输出格式:

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

输入输出样例

输入样例#1:
4
1 2 1 1
3
1 1
2 1 1
1 1
输出样例#1:
2
3

说明

对于20%的数据n,m<=10000,对于100%的数据n<=200000,m<=100000

题解

  • 听说这是道LCT的板题,蒟蒻只能躲在角落默默发抖
  • 把所有n个点分成sqrt(n)块
  • 对于每个点,记录两个量,一个是它要弹几次才能出它所在的这个块,另外一个是它弹出这个块后到哪个点
  • 这样的话,每次询问和修改的复杂度均为O(sqrt(n))

代码

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <cmath>
 5 #define N 200010
 6 using namespace std;
 7 int n,tot,num,Q,ch,k,x,p[N],bz[N],s[N],bel[N],l[1010];
 8 int calc(int x)
 9 {
10     int r=0;
11     while (1)
12     {
13         r+=bz[x];
14         if (!p[x]) break;
15         x=p[x];
16     }
17     return r;
18 }
19 int main()
20 {
21     scanf("%d",&n),num=sqrt(n),tot=n/num;
22     if (n%num) tot++;
23     for (int i=1;i<=n;i++) scanf("%d",&s[i]);
24     for (int i=1;i<=tot;i++) l[i]=(i-1)*num+1;
25     for (int i=1;i<=n;i++) bel[i]=(i-1)/num+1;
26     for (int i=n;i>0;i--)
27         if (i+s[i]>n) bz[i]=1;
28         else if (bel[i]==bel[i+s[i]]) bz[i]=bz[i+s[i]]+1,p[i]=p[i+s[i]];
29              else bz[i]=1,p[i]=i+s[i];
30     scanf("%d",&Q);
31     while (Q--)
32     {
33         scanf("%d%d",&ch,&k),k++;
34         if (ch==1) printf("%d
",calc(k));
35         else 
36         {
37             scanf("%d",&x),s[k]=x;
38             for (int i=k;i>=l[bel[k]];i--) if (bel[i]==bel[i+s[i]]) bz[i]=bz[i+s[i]]+1,p[i]=p[i+s[i]]; else bz[i]=1,p[i]=i+s[i];
39         }
40     }
41 }
原文地址:https://www.cnblogs.com/Comfortable/p/10309716.html