题解
题目中编号从 0 开始,方便起见,代码中加上 1 使得从 1 开始。
首先从 (i) 弹射 (k) 就是指 (i) 与 (i + k) 连边,对于 目标 (gt n) 的全部指向 (n + 1)。询问 (i) 时直接 (access(i, n + 1)),输出这个 Splay 的 (size) 即可。
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 200000 + 5;
int n, m;
namespace LCT
{
// PartI. Splay
int fa[maxn], ch[2][maxn], size[maxn], st[maxn], sz; bool flip[maxn];
bool inline notroot(int o) {
return (ch[0][fa[o]] == o) || (ch[1][fa[o]] == o);
}
void inline pushdown(int o) {
if(flip[o]) {
if(ch[0][o]) flip[ch[0][o]] ^= 1;
if(ch[1][o]) flip[ch[1][o]] ^= 1;
swap(ch[0][o], ch[1][o]);
flip[o] = false;
}
}
void inline pushup(int o) {
size[o] = size[ch[0][o]] + size[ch[1][o]] + 1;
}
void inline rotate(int x) {
int y = fa[x], z = fa[y], d = ch[1][y] == x;
if(notroot(y)) ch[y == ch[1][z]][z] = x; fa[x] = z;
ch[d][y] = ch[d^1][x]; if(ch[d][y]) fa[ch[d][y]] = y; ch[d^1][x] = y; fa[y] = x;
pushup(y); pushup(x);
}
void inline splay(int x) {
// printf("In splay
");
int o = x;
st[sz = 1] = o;
while(notroot(o)) st[++sz] = o = fa[o];
// printf("stack!
");
while(sz) pushdown(st[sz--]);
while(notroot(x)) {
int y = fa[x], z = fa[y];
// printf("y = %d, z = %d
", y, z);
if(notroot(y)) rotate(((ch[0][z] == y) ^ (ch[0][y] == x)) ? x : y);
rotate(x);
}
pushup(x);
}
// debug
void inline debug() {
for(int i = 1; i <= n + 1; ++i) {
printf("%d:"%d"<%d>(%d)[%d, %d]
", i, flip[i], size[i], fa[i], ch[0][i], ch[1][i]);
}
}
// PartII. LCT
void inline access(int x) {
for(int y = 0; x; y = x, x = fa[x]) {
splay(x);
ch[1][x] = y;
pushup(x);
}
}
void inline makeroot(int x) {
// printf("In makeroot.
");
access(x);
// printf("access ok.
");
// debug();
splay(x);
flip[x] ^= 1;
}
void inline split(int x, int y) {
makeroot(x);
// printf("makeroot ok.
");
// debug();
access(y); splay(y);
}
void inline link(int x, int y) {
makeroot(x);
fa[x] = y;
}
void inline cut(int x, int y) {
split(x, y);
fa[x] = ch[0][y] = 0;
pushup(y);
}
}
int opt, i, k;
int lk[maxn];
void inline Init()
{
scanf("%d", &n);
for(int i = 1; i <= n; ++i) {
scanf("%d", &k);
lk[i] = LCT::fa[i] = (i + k > n) ? n + 1 : i + k;
}
scanf("%d", &m);
}
void inline Solve()
{
while(m--) {
// LCT::debug();
scanf("%d %d", &opt, &i);
++i;
if(opt == 1) {
LCT::split(i, n + 1);
printf("%d
", LCT::size[n + 1] - 1);
} else {
scanf("%d", &k);
LCT::cut(i, lk[i]);
LCT::link(i, lk[i] = (i + k > n) ? n + 1 : i + k);
}
// printf("ok.
");
}
}
int main()
{
Init();
Solve();
return 0;
}