Network,闇の連鎖

仔细分析,考虑树上,若断一条树边 (u,v)(u, v),则会分成两个连通块

  • 两个连通块之间有 00 条附加边,则任意再切一条
  • 两个连通块之间有 11 条附加边,则只能切特定的一条
  • 两个连通块之间有 2\geq 2 条附加边,无方案

如何快速计数?

记附加边为 (x,y)(x,y) ,发现 (u,x),(v,y)(u, x),(v,y) 两条路径不相交则 (x,y)(x,y)(u,v)(u,v) 有影响

即,附加边 (x,y)(x,y) 对于主要边树上 (x,y)(x,y) 路径上所有边都有影响

或者说,附加边 (x,y)(x,y) 会在树上产生环,如果切环上的边就必须把 (x,y)(x,y) 切掉

然后就是树上边差分

POJ 上 TLE 了,但是本地没问题,复杂度(应该)没挂?

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
#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <deque>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <utility>
#include <vector>
#define rep(i, l, r) for (int i = (l); i <= (r); ++i)
#define per(i, l, r) for (int i = (l); i >= (r); --i)
using std::cerr;
using std::cin;
using std::cout;
using std::endl;
using std::make_pair;
using std::pair;
typedef pair<int, int> pii;
typedef long long ll;
typedef unsigned int ui;

const int N = 100010;

std::vector<int> g[N], ng[N];

int fa[20][N], dep[N], val[N];

void dfs(int u) {
for (int i = 0; i < g[u].size(); ++i) {
int v = g[u][i];
if (v == fa[0][u]) continue;
fa[0][v] = u;
dep[v] = dep[u] + 1;
dfs(v);
}
}

int up(int u, int l) {
for (int i = 19; i >= 0; --i) {
if (l >= (1 << i)) u = fa[i][u], l -= 1 << i;
}
return u;
}

int q(int u, int v) {
if (dep[u] < dep[v]) std::swap(u, v);
u = up(u, dep[u] - dep[v]);
if (u == v) return u;
for (int i = 19; i >= 0; --i)
if (fa[i][u] != fa[i][v]) u = fa[i][u], v = fa[i][v];
return fa[0][u];
}

int n, m, ans;

int calc(int u) {
int ret = 0;
for (int i = 0; i < g[u].size(); ++i) {
int v = g[u][i];
if (v == fa[0][u]) continue;
v = calc(v);
if (v == 0)
ans += m;
else if (v == 1)
ans += 1;
ret += v;
}
return ret + val[u];
}

int main() {
#ifdef LOCAL
freopen("input", "r", stdin);
#endif
std::ios::sync_with_stdio(false);
cout.tie(0);
int u, v;
cin >> n >> m;
rep(i, 2, n) {
cin >> u >> v;
g[u].push_back(v), g[v].push_back(u);
}
dep[1] = 1;
dfs(1);
// cerr << "dfs over" << endl;
rep(k, 1, 19) rep(i, 1, n) fa[k][i] = fa[k - 1][fa[k - 1][i]];
// cerr << "dfs over" << endl;

rep(i, 1, m) {
cin >> u >> v;
val[u] += 1;
val[v] += 1;
val[q(u, v)] -= 2;
}
calc(1);
cout << ans;
return 0;
}
作者

Gesrua

发布于

2019-07-15

更新于

2020-11-21

许可协议