0%

noip2015提高组运输计划

首先 5 分还是很好拿的。只要dfs一下,记录从根到i的最大值和路径权值和,然后对于给出的数a, b, 输出sum[a] + sum[b] - max(mx[a], mx[b])

然后直接讲满分做法吧

二分 + 链长。
答案单调所以二分。
可以用树上差分 + 树剖 / 倍增 来 check.

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
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 3e5 + 10;
struct edge
{
int next, to, dis;
} e[2 * N], q[2 * N];
struct length
{
int len, lca, u, v;
} len[N];
int head[N], cnt, headq[N], dis[N], maxlen, n, m, a[N], ans, s[N], num, ret, f[N]; //一堆变量
bool vis[N];
inline int read()
{
int x = 0, ch = getchar();
while (ch > '9' || ch < '0') ch = getchar();
while (ch >= '0' && ch <= '9')
x = (x << 3) + (x << 1) + (ch ^ '0'), ch = getchar();
return x;
}
inline void add(int x, int y, int d)
{
e[++cnt].next = head[x];
e[cnt].to = y;
e[cnt].dis = d;
head[x] = cnt;
}
inline void add2(int x, int y)
{
q[++cnt].next = headq[x], q[cnt].to = y, headq[x] = cnt;
}
int find(int x)
{
return f[x] == x ? f[x] : f[x] = find(f[x]);
}
void dfs(int u, int pre)
{
for (int i = head[u]; i; i = e[i].next)
{
int v = e[i].to;
if (v == pre)
continue;
dfs(v, u);
s[u] += s[v];
}
if (s[u] == num && a[u] > ret) ret = a[u];
}
inline bool check(int x)
{
memset(s, 0, sizeof(s));
num = ret = 0;
for (int i = 1; i <= m; i++)
if (len[i].len > x)
{
s[len[i].u]++;
s[len[i].v]++;
s[len[i].lca] -= 2;
num++;
}
dfs(1, 0);
if (maxlen - ret > x)
return 0;
return 1;
}
void tarjan(int u, int pre)
{
for (int i = head[u]; i; i = e[i].next)
{
int v = e[i].to;
if (v == pre)
continue;
dis[v] = dis[u] + e[i].dis;
tarjan(v, u);
a[v] = e[i].dis;
int f1 = find(v);
int f2 = find(u);
if (f1 != f2)
f[f1] = find(f2);
vis[v] = 1;
}
for (int i = headq[u]; i; i = q[i].next)
if (vis[q[i].to])
{
int p = (i + 1) >> 1;
len[p].lca = find(q[i].to);
len[p].len = dis[u] + dis[q[i].to] - 2 * dis[len[p].lca];
maxlen = max(maxlen, len[p].len);
}
}
int main()
{
n = read(), m = read();
for (int i = 1; i < n; i++)
{
int ai = read(), bi = read(), ti = read();
add(ai, bi, ti);
add(bi, ai, ti);
}
for (int i = 1; i <= n; i++)
f[i] = i;
cnt = 0;
for (int i = 1; i <= m; i++)
{
int x = read(), y = read();
len[i].u = x;
len[i].v = y;
add2(x, y);
add2(y, x);
}
tarjan(1, 0);
int l = 0, r = maxlen, mid;
while (l <= r)
{
mid = (l + r) >> 1;
if (check(mid))
{
r = mid - 1;
ans = mid;
}
else
l = mid + 1;
}
printf("%d\n", ans);
return 0;
}

欢迎关注我的其它发布渠道