bzoj 3331 [BeiJing2013]压力

题目描述

给定一张 $n$ 个点 $m$ 条边的无向连通图,还有 $q$ 个点对,需要计算每个点是多少个点对的必经点

$n\le 10^5,m\le 10^6$

Solution

按照圆方树的性质,必经点就是这两个点在圆方树上的简单路径上的圆点,差分一下就好了

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
#include <iostream>
#include <stack>
#define maxn 100010
#define maxm 200010
#define Maxn 200010
#define Maxm 200010
using namespace std;

int n, m, q;

struct Edge {
int to, next;
} e[maxm * 2], E[Maxm * 2]; int head[maxn], c1, Head[Maxn], c2;
inline void add_edge(int u, int v) {
e[c1].to = v; e[c1].next = head[u]; head[u] = c1++;
}

inline void add_Edge(int u, int v) {
E[c2].to = v; E[c2].next = Head[u]; Head[u] = c2++;
}

inline void Add_Edge(int u, int v) {
add_Edge(u, v); add_Edge(v, u);
}

int dfn[maxn], low[maxn], num; stack<int> S;
void tarjan(int u, int fa) {
static int cnt = 0;
dfn[u] = low[u] = ++cnt; S.push(u);
for (int i = head[u]; ~i; i = e[i].next) {
int v = e[i].to; if (v == fa) continue;
if (!dfn[v]) {
tarjan(v, u); low[u] = min(low[u], low[v]);
if (low[v] >= dfn[u]) {
++num; int t;
do {
t = S.top(); S.pop();
Add_Edge(t, num);
} while (t != v);
Add_Edge(u, num);
}
}
else low[u] = min(low[u], dfn[v]);
}
}

int f[Maxn][21], dis[Maxn], dep[Maxn];
void dfs(int u, int fa) {
for (int i = Head[u]; ~i; i = E[i].next) {
int v = E[i].to; if (v == fa) continue;
dep[v] = dep[u] + 1; f[v][0] = u;
dfs(v, u);
}
}

void init_lca(int n) {
for (int j = 1; j <= 20; ++j)
for (int i = 1; i <= n; ++i) f[i][j] = f[f[i][j - 1]][j - 1];
}

inline int get_lca(int x, int y) {
if (dep[x] < dep[y]) swap(x, y);
for (int i = 20; ~i; --i)
if (dep[f[x][i]] >= dep[y]) x = f[x][i];
if (x == y) return x;
for (int i = 20; ~i; --i)
if (f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
return f[x][0];
}

void Dfs(int u, int fa) {
for (int i = Head[u]; ~i; i = E[i].next) {
int v = E[i].to; if (v == fa) continue;
Dfs(v, u); dis[u] += dis[v];
}
}

int main() { fill(head, head + maxn, -1); fill(Head, Head + Maxn, -1);
ios::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);

cin >> n >> m >> q; num = n;
for (int i = 1; i <= m; ++i) {
int x, y; cin >> x >> y;
add_edge(x, y); add_edge(y, x);
} tarjan(1, 0);
dep[1] = 1; dfs(1, 0); init_lca(num);
for (int i = 1; i <= q; ++i) {
int x, y; cin >> x >> y; int l = get_lca(x, y);
++dis[x]; ++dis[y]; --dis[l]; --dis[f[l][0]];
} Dfs(1, 0);
for (int i = 1; i <= n; ++i) cout << dis[i] << "\n";
return 0;
}