题面

大秦为你打开题目传送门

题目描述

给一棵n个节点的树, 节点编号为1~n。

给定m条路径,问最多可以选多少条路径而且他们不经过同一个点。

题解

这道题目很显而易见是一道贪心题目,我们借鉴类似于在区间上选择最多线段的题目的思路,不难想到策略:选 LCA 尽可能深的路径。

代码

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
/**
* @file HDU4912
* @author Zhoumouren
* @brief
* @version 0.1
* @date 2024-08-22
*
* @copyright Copyright (c) 2024

Tanxin. Use LCA sort form deep to not deep.

*/

#pragma GCC optimize(2)
#pragma GCC optimize(3, "Ofast", "inline")
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef __int128 int128;

namespace FastIO
{
char buf[1 << 20], * p1, * p2;
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 20, stdin), p1 == p2) ? EOF : *p1++)
template<typename T> inline T read(T& x) {
x = 0;
int f = 1;
char ch;
while (!isdigit(ch = getchar())) if (ch == '-') f = -1;
while (isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
x *= f;
return x;
}
template<typename T, typename... Args> inline void read(T& x, Args &...x_) {
read(x);
read(x_...);
return;
}
inline ll read() {
ll x;
read(x);
return x;
}
inline void read(char* s) {
scanf("%s", s + 1);
}
};
using namespace FastIO;

const int N = 1e5 + 10;

struct Edge {
int to, nt;
Edge() {}
Edge(int to, int nt) : to(to), nt(nt) {}
}e[N << 1];
int hd[N], cnte;
void AddEdge(int u, int v) {
e[++cnte] = Edge(v, hd[u]);
hd[u] = cnte;
}

int n, m;
pair<int , pair<int , int > >a[N];

inline void Input() {
read(n, m);
int u, v;
for(int i = 1; i < n; i++) {
read(u, v);
AddEdge(u, v);
AddEdge(v, u);
}
for(int i = 1; i <= m; i++) {
read(a[i].second.first, a[i].second.second);
}
}

int dep[N];
int st[N][20];
int vis[N];

inline void Dfs(int u, int fa) {
dep[u] = dep[fa] + 1;
st[u][0] = fa;
for(int i = 1; i < 20; i++) {
st[u][i] = st[st[u][i - 1]][i - 1];
}
for(int i = hd[u]; i; i = e[i].nt) {
int v = e[i].to;
if(v == fa) continue;
Dfs(v, u);
}
}

inline int LCA(int u, int v) {
if(dep[u] < dep[v]) swap(u, v);
for(int i = 19; i >= 0; i--) {
if(dep[st[u][i]] >= dep[v]) {
u = st[u][i];
}
}
if(u == v) return u;
for(int i = 19; i >= 0; i--) {
if(st[u][i] != st[v][i]) {
u = st[u][i], v = st[v][i];
}
}
return st[u][0];
}

inline void Visit(int u) {
vis[u] = 1;
for(int i = hd[u]; i ; i = e[i].nt) {
int v = e[i].to;
if(vis[v] || v == st[u][0]) continue;
Visit(v);
}
}

inline void Work() {
Dfs(1, 0);
// for(int i = 1; i <= n; i++) {
// cout << dep[i] << ' ';
// }
// cout << endl;
for(int i = 1; i <= m; i++) {
a[i].first = LCA(a[i].second.first, a[i].second.second);
cout << a[i].first << ' ' << a[i].second.first << ' ' << a[i].second.second << endl;
}
sort(a + 1, a + m + 1, [](pair<int , pair<int , int > > a, pair<int , pair<int , int > > b) {
return dep[a.first] > dep[b.first];
});
int ans = 0;
for(int i = 1; i <= m; i++) {
if(!vis[a[i].second.first] && !vis[a[i].second.second]){
ans++;
Visit(a[i].first);
}
}
printf("%d", ans);
}

int main() {
int T = 1;
while (T--) {
Input();
Work();
}
return 0;
}