某天,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的情况,你都要输出一个需要的步数,占一行。
4
1 2 1 1
3
1 1
2 1 1
1 1
2
3
对于20%的数据n,m<=10000,对于100%的数据n<=200000,m<=100000
设绵羊在节点 n+1 n + 1 表示被“弹飞”,容易发现,如果我们把一个点与它的后继连起来的话,就形成了一颗树(每个节点都有唯一的后继,类同于树中每个节点都有唯一的父节点),然后修改操作就变成了删边和连边, 查询操作变成了查询两点之间距离——这就是一个LCT的模板题了。
复杂度 O(MlogN) O ( M l o g N )
但是,这道题还可以分块!
把原序列分成 n−−√ n 块,每块长为 n−−√ n ,每个节点记录需要弹多少次能到达下一个的块的哪个节点;修改时暴力修改块内所有与被修改节点相关的节点信息,查询时在块之间统计即可。
复杂度 O(MN−−√)=O(4.48×107) O ( M N ) = O ( 4.48 × 10 7 ) ,可过!
#include
#include
#define lson tr[id].son[0]
#define rson tr[id].son[1]
using namespace std;
const int N = 200005;
int n, a, b, c, m, k[N];
struct Splay{
int son[2], fa, size;
bool rev;
}tr[N];
struct OPT_LCT{
int sta[N], top;
inline void pushup(int id){
tr[id].size = tr[lson].size + tr[rson].size + 1;
}
inline void pushdown(int id){
if(tr[id].rev){
if(lson){
tr[lson].rev ^= 1;
swap(tr[lson].son[0], tr[lson].son[1]);
}
if(rson){
tr[rson].rev ^= 1;
swap(tr[rson].son[0], tr[rson].son[1]);
}
tr[id].rev = 0;
}
}
inline int which(int x){ return tr[tr[x].fa].son[1] == x; }
inline int isRoot(int x){ return tr[tr[x].fa].son[0] != x && tr[tr[x].fa].son[1] != x; }
inline void rotate(int x, int kind){
int y = tr[x].fa, z = tr[y].fa, B = tr[x].son[kind];
if(!isRoot(y)) tr[z].son[which(y)] = x;
tr[x].son[kind] = y, tr[y].son[!kind] = B;
tr[B].fa = y, tr[y].fa = x, tr[x].fa = z;
pushup(y), pushup(x);
}
inline void splay(int x){
sta[top = 1] = x;
for(int i = x; !isRoot(i); i = tr[i].fa) sta[++top] = tr[i].fa;
while(top) pushdown(sta[top--]);
while(!isRoot(x)){
int y = tr[x].fa, z = tr[y].fa;
pushdown(z), pushdown(y), pushdown(x);
int dir1 = !which(x), dir2 = !which(y);
if(isRoot(y)) rotate(x, dir1);
else{
if(dir1 == dir2) rotate(y, dir2);
else rotate(x, dir1);
rotate(x, dir2);
}
}
}
inline void access(int x){
int y = 0;
while(x){
splay(x);
tr[x].son[1] = y;
pushup(x);
y = x, x = tr[x].fa;
}
}
inline void makeRoot(int x){
access(x), splay(x);
tr[x].rev ^= 1;
swap(tr[x].son[0], tr[x].son[1]);
pushup(x);
}
inline void link(int x, int y){
makeRoot(x), access(y), splay(y);
tr[x].fa = y;
}
inline void cut(int x, int y){
makeRoot(x), access(y), splay(y);
tr[y].son[0] = tr[x].fa = 0;
pushup(y);
}
inline int query(int x){
makeRoot(n+1), access(x), splay(x);
return tr[x].size - 1;
}
}LCT;
int main(){
scanf("%d", &n);
for(int i = 1; i <= n + 1; i++) tr[i].size = 1;
for(int i = 1; i <= n; i++){
scanf("%d", &k[i]);
LCT.link(i, i+k[i] > n ? n+1 : i+k[i]);
}
scanf("%d", &m);
while(m--){
scanf("%d%d", &a, &b);
b++;
if(a == 1) printf("%d\n", LCT.query(b));
else if(a == 2){
scanf("%d", &c);
LCT.cut(b, b+k[b] > n ? n+1 : b+k[b]);
LCT.link(b, b+c > n ? n+1 : b+c);
k[b] = c;
}
}
return 0;
}
#include
#include
#include
#include
using namespace std;
inline int read(){
int x = 0;
bool fl = 1;
char ch = getchar();
while(ch < '0' || ch > '9'){
if(ch == '-') fl = 0;
ch = getchar();
}
while(ch >= '0' && ch <= '9'){
x = (x << 1) + (x << 3) + ch - '0';
ch = getchar();
}
return fl ? x : -x;
}
const int N = 200005;
int n, q, k[N], opt, a, b, block[N<<1], ans, l[N], r[N];
struct G{
int cnt, to;
}g[N];
int main(){
memset(l, 0x7f, sizeof l);
memset(r, -1, sizeof r);
n = read();
for(int i = 1; i <= n; i++){
k[i] = read();
block[i] = (i-1) / sqrt(n) + 1;
l[block[i]] = min(l[block[i]], i);
r[block[i]] = max(r[block[i]], i);
}
for(int i = 1; i <= n; i++){
int now = i;
while(block[now] == block[i]){
g[i].cnt++;
now += k[now];
}
g[i].to = now;
}
q = read();
while(q--){
opt = read(), a = read(); a++;
if(opt == 1){
ans = 0;
int now = a;
while(now <= n){
ans += g[now].cnt;
now = g[now].to;
}
printf("%d\n", ans);
}
else if(opt == 2){
b = read();
k[a] = b;
for(int i = a; i >= l[block[a]]; i--){
if(block[i] == block[i+k[i]]){
g[i].cnt = g[i+k[i]].cnt + 1;
g[i].to = g[i+k[i]].to;
}
else{
g[i].cnt = 1;
g[i].to = i + k[i];
}
}
}
}
return 0;
}