胡闹 老园丁与小司机

题目大意

你是一个资本家,你的花园结构是一棵$n\le3\times10^5$个节点的树,有$m\le 3\times10^5$个无产阶级可以帮你标记路径,但只能是从一个节点到它的某一个祖先。

雇佣某个无产阶级需要工资。你想知道让你的花园里面所有的边都被标记所需要支付的最小工资。

如果全部雇佣也不够,你就会放 弃 思 考,认为需要$-1$的工资。

解析

我 放 弃 了 思 考。

考虑树形$dp$,用左偏树维护决策。

发现可以维护无产阶级深度最高点为关键字的左偏树来维护决策,无脑上代码即可。

注意打标记。

Code

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
#define REP(i, s, e) for (int i = s; i <= e ; i++)
#define DEBUG fprintf(stderr, "Passing [%s] in Line %d\n", __FUNCTION__, __LINE__)

#include <iostream>
#include <cstdio>
#define int long long

using namespace std;
const int maxn = 300000 + 10, maxm = maxn, inf = 1ll << 40;

int bg[maxn], ne[maxm << 1], to[maxm << 1], e;
void add(int x, int y)
{
e++;
to[e] = y;
ne[e] = bg[x];
bg[x] = e;
}
int depth[maxn];
void dfs(int x, int fa = -1)
{
for (int i = bg[x]; i ; i = ne[i])
if (to[i] ^ fa)
{
depth[to[i]] = depth[x] + 1;
dfs(to[i], x);
}
}

struct worker
{
int up, w, ne;
}p[maxm << 1];
int cur = 300000;
void insert(int x, int up, int w)
{
p[++cur] = (worker){up, w, p[x].ne};
p[x].ne = cur;
}

struct heap *null;
heap* merge(heap *x, heap *y){};
struct heap
{
int up, f, Min, tag, dis;
heap *l, *r;
void pushdown()
{
if (tag)
{
f += tag;
Min += tag;
l -> tag += tag;
r -> tag += tag;
tag = 0;
}
}
void pushup()
{
Min = min(f, min(l -> Min + l -> tag, r -> Min + r -> tag));
if (l -> dis < r -> dis) swap(l, r);
dis = r -> dis + 1;
}
void pop() {*this = merge(l, r);}
}pool[maxn], *now = pool, *root[maxn];
heap* merge(heap *x, heap *y)
{
if (x == null) return y;
if (y == null) return x;
x -> pushdown();y -> pushdown();
if (x -> up <= y -> up) swap(x, y);
x -> r = merge(x -> r, y);
x -> pushup();
return x;
}
void solve(int x, int fa = -1)
{
int sum = 0;
for (int i = bg[x]; i ; i = ne[i])
if (to[i] ^ fa)
{
solve(to[i], x);
while (root[to[i]] -> up >= depth[to[i]])
root[to[i]].pop();
if (root[to[i]] == null)
{
cout << -1 << endl;
exit(0);
}
sum += root[to[i]] -> Min;
}
for (int i = p[x].ne; i ; i = p[i].ne)
{
*now = (heap) {p[i].up, sum + p[i].w, sum + p[i].w, 0, 1, null, null};
root[x] = merge(root[x], now++);
}
for (int i = bg[x]; i ; i = ne[i])
if (to[i] ^ fa)
{
int Min = root[to[i]] -> Min;
root[to[i]] -> tag += sum - Min;
root[x] = merge(root[x], root[to[i]]);
}
if (root[x] == null)
{
cout << -1 << endl;
exit(0);
}
}

int m, n, k;

signed main()
{
#ifndef ONLINE_JUDGE
freopen("A.in", "r", stdin);
freopen("A.out", "w", stdout);
#endif
cin >> n >> m;
REP(i, 2, n)
{
int x, y;
scanf("%lld%lld", &x, &y);
add(x, y);add(y, x);
}
depth[1] = 1;
dfs(1);
REP(i, 1, m)
{
int u, v, w;
scanf("%lld%lld%lld", &u, &v, &w);
insert(u, depth[v], w);
}
null = new heap;
null -> l = null -> r = null;
null -> Min = inf;
REP(i, 1, n) root[i] = null;
solve(1);
printf("%lld\n", root[1] -> Min + root[1] -> tag);
return 0;
}

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×