树链剖分。

Table of Contents

  1. Description
  2. Solution

Description

有一张无向图, 定义关键路径为删去后图不连通的路径, 现在要依次删去一些边, 随时有一些询问, 求两点间的关键路径数.

Solution

这种题首先要想到倒序处理, 因为删边不好做.

然后来考虑题目的性质, 加入这张图最后被删得只剩一颗树了, 那么每一次加边, 都会让边两端路径上的关键路径变为0.

而在一颗树上两点之间关键路径数都是1.

区间求和, 修改? 树链剖分啊.

首先删边, 然后把剩下的图跑出来一颗生成树, 再用非树边更新, 接着依次执行操作和询问即可.

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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cctype>

using namespace std;

const int maxn = 30005;
const int maxm = 1e+5 + 5;

struct option
{
int typ, a, b;
}q[maxn + 10005];
struct edge
{
int to, nxt; bool ban;
}e[maxm << 1];
int n, m, ptr, lnk[maxn], opn, cnt;
int dfn[maxn], top[maxn], f[maxn], mxson[maxn], siz[maxn];
int ans[maxn], dep[maxn];

inline void add(int bgn, int end) {
e[ptr] = (edge) {end, lnk[bgn], 0};
lnk[bgn] = ptr; ptr++;
e[ptr] = (edge) {bgn, lnk[end], 0};
lnk[end] = ptr; ptr++;
}
inline int rd() {
register int x = 0, f = 0, c = getchar();
while (!isdigit(c)) {
if (c == '-') f = 1;
c = getchar();
}
while (isdigit(c)) x = x * 10 + (c ^ 48), c = getchar();
return f ? -x : x;
}
void dfs(int x, int fa) {
//printf("%d\n", x);
siz[x] = 1;
f[x] = fa;
dep[x] = dep[fa] + 1;
for (int p = lnk[x]; ~p; p = e[p].nxt) {
int y = e[p].to;
if (y == fa || e[p].ban || dep[y]) continue;
dfs(y, x);
siz[x] += siz[y];
if (siz[y] > siz[mxson[x]]) mxson[x] = y;
}
}
void dfs2(int x, int init) {
dfn[x] = ++cnt;
top[x] = init;
if (!mxson[x]) return;
dfs2(mxson[x], init);
for (int p = lnk[x]; ~p; p = e[p].nxt) {
int y = e[p].to;
if (f[y] != x || y == mxson[x] || e[p].ban) continue;
dfs2(y, y);
}
}

int s[maxn << 2], tag[maxn << 2];
inline void pushup(int cur) {
s[cur] = s[cur << 1] + s[cur << 1|1];
}
inline void pushdown(int cur) {
if (tag[cur]) {
s[cur << 1] = s[cur << 1|1] = 0;
tag[cur << 1] = tag[cur << 1|1] = 1;
tag[cur] = 0;
}
}
void build(int cur, int l, int r) {
if (l == r) {
s[cur] = 1;
return;
}
int mid = (l + r) >> 1;
build(cur << 1, l, mid);
build(cur << 1|1, mid + 1, r);
pushup(cur);
}
void update(int cur, int l, int r, int L, int R) {
if (L <= l && r <= R) {
s[cur] = 0;
tag[cur] = 1;
return;
}
int mid = (l + r) >> 1; pushdown(cur);
if (L <= mid) update(cur << 1, l, mid, L, R);
if (R > mid) update(cur << 1|1, mid + 1, r, L, R);
pushup(cur);
}
int query(int cur, int l, int r, int L, int R) {
if (L <= l && r <= R) return s[cur];
int mid = (l + r) >> 1, ret = 0; pushdown(cur);
if (L <= mid) ret += query(cur << 1, l, mid, L, R);
if (R > mid) ret += query(cur << 1|1, mid + 1, r, L, R);
return ret;
}
void updt(int x, int y) {
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) swap(x, y);
update(1, 1, n, dfn[top[x]], dfn[x]);
x = f[top[x]];
}
if (dep[x] > dep[y]) swap(x, y);
if (dep[x] != dep[y]) update(1, 1, n, dfn[x] + 1, dfn[y]);
}
void efs(int x) {
//printf("e%d\n", x);
for (int p = lnk[x]; ~p; p = e[p].nxt) {
int y = e[p].to;
if (e[p].ban) continue;
if (f[y] == x) efs(y);
if (y != f[x] && dep[y] < dep[x])
updt(x, y);
}
}
int queryt(int x, int y) {
int ret = 0;
//printf("%d %d\n", x, y);
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) swap(x, y);
//printf("q %d %d\n", dfn[top[x]], dfn[x]);
ret += query(1, 1, n, dfn[top[x]], dfn[x]);

x = f[top[x]];
}
if (dep[x] > dep[y]) swap(x, y);
//printf("q %d %d\n", dfn[x], dfn[y]);
ret += query(1, 1, n, dfn[x], dfn[y]);
ret -= query(1, 1, n, dfn[x], dfn[x]);
return ret;
}

int main() {
n = rd(); m = rd();
memset(lnk, -1, sizeof lnk);
int a, b;
for (int i = 1; i <= m; ++i) {
a = rd(); b = rd();
add(a, b);
}
int c;
while (true) {
c = rd(); if (c == -1) break;
q[++opn].typ = c;
q[opn].a = rd(); q[opn].b = rd();
if (!c) {
for (int p = lnk[q[opn].a]; ~p; p = e[p].nxt) {
if (e[p].to == q[opn].b) {
//printf("%d %d\n", e[p].to, q[opn].b);
//puts("try");
e[p].ban = e[p ^ 1].ban = 1;
break;
}
}
}
}
dfs(1, 0);
dfs2(1, 1);
build(1, 1, n);
efs(1);
for (int i = opn; i; --i) {
//puts("try");
if (q[i].typ) {
ans[i] = queryt(q[i].a, q[i].b);
} else {
updt(q[i].a, q[i].b);
}
}
for (int i = 1; i <= opn; ++i) {
if (q[i].typ) printf("%d\n", ans[i]);
}
return 0;
}