[BZOJ-2002]弹飞绵羊

Description

有n个装置,在第i个装置上会被弹到第i+X[i]个装置上,弹到大于n的装置即视为弹飞。
询问操作询问在一个装置弹几次会被弹飞,修改操作会修改X值。

Solution

这是一道[HNOI2010]的题。
每次i和i+X[i]连边,从一个点走多少步走到n+1节点即为答案。
每次修改时先删边再加边即可。

Notice

注意原题中编号是0~n-1的。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define sqz main
#define ll long long
#define rep(i, a, b) for (int i = (a); i <= (b); i++)
#define per(i, a, b) for (int i = (a); i >= (b); i--)
#define Rep(i, a, b) for (int i = (a); i < (b); i++)
#define travel(i, u) for (int i = head[u]; ~i; i = edge[i].next)

const ll INF = 1e9, Mo = 998244353;
const int N = 300000;
const double eps = 1e-6;
namespace slow_IO
{
ll read()
{
ll x = 0; int zf = 1; char ch = getchar();
while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
if (ch == '-') zf = -1, ch = getchar();
while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
return x * zf;
}
void write(ll y)
{
if (y < 0) putchar('-'), y = -y;
if (y > 9) write(y / 10);
putchar(y % 10 + '0');
}
}
using namespace slow_IO;

int X[N + 5];
struct LinkCutTree
{
int Fa[N + 5], rev[N + 5], Son[N + 5][2], Size[N + 5], Stack[N + 5], top;
inline void up(int u)
{
Size[u] = Size[Son[u][0]] + Size[Son[u][1]] + 1;
}
inline void down(int u)
{
if (!rev[u]) return;
rev[Son[u][0]] ^= 1, rev[Son[u][1]] ^= 1, rev[u] ^= 1;
swap(Son[u][0], Son[u][1]);
}
inline int isroot(int u)
{
return (Son[Fa[u]][0] != u && Son[Fa[u]][1] != u);
}

inline void Rotate(int x)
{
int y = Fa[x], z = Fa[y];
int l = Son[y][1] == x, r = l ^ 1;
if (!isroot(y)) Son[z][Son[z][1] == y] = x;
Son[y][l] = Son[x][r], Fa[Son[x][r]] = y;
Son[x][r] = y, Fa[y] = x, Fa[x] = z;
up(y); up(x);
}
inline void Splay(int x)
{
Stack[top = 1] = x;
for (int y = x; !isroot(y); y = Fa[y]) Stack[++top] = Fa[y];
per(i, top, 1) down(Stack[i]);
while (!isroot(x))
{
int y = Fa[x], z = Fa[y];
if (!isroot(y))
{
if ((Son[y][1] == x) ^ (Son[z][1] == y)) Rotate(x);
else Rotate(y);
}
Rotate(x);
}
}

inline void Access(int u)
{
for (int last = 0; u; last = u, u = Fa[u])
Splay(u), Son[u][1] = last, up(u);
}
inline void Make_Root(int u)
{
Access(u); Splay(u); rev[u] ^= 1;
}
inline int Find_Root(int u)
{
Access(u), Splay(u);
while (Son[u][0]) u = Son[u][0];
return u;
}

inline void Split(int x, int y)
{
Make_Root(x), Access(y), Splay(y);
}
inline void Link(int x, int y)
{
Make_Root(x);
if (Find_Root(y) == x) return;
Fa[x] = y;
}
inline void Cut(int x, int y)
{
Make_Root(x);
if (Find_Root(y) != x || Fa[x] != y || Son[x][1]) return;
Fa[x] = Son[y][0] = 0;
}
}LCT;

int sqz()
{
int n = read();
rep(i, 1, n) X[i] = read();
rep(i, 1, n) LCT.Link(i, i + X[i] <= n ? i + X[i] : n + 1);
int q = read();
while (q--)
{
int op = read();
if (op == 1)
{
int x = read() + 1;
LCT.Split(x, n + 1);
printf("%d\n", LCT.Size[n + 1] - 1);
}
else
{
int x = read() + 1, y = read();
LCT.Cut(x, x + X[x] <= n ? x + X[x] : n + 1);
LCT.Link(x, x + y <= n ? x + y : n + 1); X[x] = y;
}
}
}
文章目录
  1. 1. Description
  2. 2. Solution
  3. 3. Notice
  4. 4. Code