题面
Description
某天,$Lostmonkey$发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。游戏一开始,$Lostmonkey$在地上沿着一条直线摆上$n$个装置,每个装置设定初始弹力系数$k_i$,当绵羊达到第$i$个装置时,它会往后弹$k_i$步,达到第$i+k_i$个装置,若不存在第$i+k_i$个装置,则绵羊被弹飞。绵羊想知道当它从第$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 \leq 10000$,对于$100\%$的数据$n \leq 200000,m \leq 100000$
Output
对于每个$i=1$的情况,你都要输出一个需要的步数,占一行。
Sample Input
1 | 4 |
Sample Output
1 | 2 |
分析
据说是$LCT$裸题,然而本蒟蒻并不会,考虑数据范围,$n \leq 200000$,可以用$O(n \sqrt n)$的分块大法。
分块后怎么做呢?
我们记录每一个点跳出它所在的块所需的弹跳次数和它跳出当前块以后落在哪一块。于是我们发现当我们修改一个点$p$以后,我们只需要修改这个块内在点$p$之前的点(准确的说,是块内中途会跳到$p$的点),因为每个点记录的东西只管它跳出它所在的块的一系列状态,至于它后面的命运是不管的。
初始化的代码如下。
1 | inline void init() //所有初始化工作 jumptime[i]表示i点跳出块所需的次数,outplace[i]表示i点跳出块以后的位置 |
修改的代码如下
1 | inline void change(int p,int k) |
有了这个想法以后询问就十分显然了
从$p$点开始跳,用$ans$变量记录次数,使$p$不断跳跃跳出它所在的块,同时$ans$加上跳出去需要的步数,直到跳出去。
代码如下
1 | inline int query(int p) |
Code
1 |
|
速度还行。