洛谷4114 QTree1

很明显这是一道树剖题

但是,树剖是在点上进行的操作,如何把它转化到边上呢?

不难发现,每一个点与他的父亲节点之间仅有唯一的一条边

于是我们可以把这条边的边权转化为这个儿子节点的点权。

然后还有一点要注意

查询时,我们是不能查询到$(u, v)$的LCA的
因为$LCA$的点权是$LCA与$fa[LCA]4之间的边权

而我们并没有统计这鬼东西

怎么办呢?

注意到当$top[u] = top[v]$时,$v$就是$u$的$LCA$

所以我们此时查询$(dfn[v+1], dfn[u])$即可

代码:

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
153
154
155
156
157
158
159
#include <bits/stdc++.h>
const int MaxN = 500010;
struct edge
{
int next, to, dis;
};
struct node
{
int max;
int l, r;
};
edge e[MaxN << 1];
int n, cnt, dfsnum;
int a[MaxN], head[MaxN], dep[MaxN], fa[MaxN], size[MaxN];
int hson[MaxN], dfn[MaxN], top[MaxN], from[MaxN], to[MaxN], pre[MaxN];
struct SegmentTree
{
node t[MaxN << 2];
inline void pushup(int id) { t[id].max = std::max(t[id << 1].max, t[id << 1 | 1].max); }
inline void build(int id, int l, int r)
{
t[id].l = l, t[id].r = r;
if (l == r)
{
t[id].max = a[pre[l]];
return;
}
int mid = (l + r) >> 1;
build(id << 1, l, mid);
build(id << 1 | 1, mid + 1, r);
pushup(id);
}
inline void modify(int id, int l, int r, int val)
{
if (t[id].l > r || t[id].r < l)
return;
if (l <= t[id].l && t[id].r <= r)
{
t[id].max = val;
return;
}
modify(id << 1, l, r, val);
modify(id << 1 | 1, l, r, val);
pushup(id);
}
inline int query(int id, int l, int r)
{
if (l > t[id].r || r < t[id].l)
return 0;
if (l <= t[id].l && t[id].r <= r)
return t[id].max;
return std::max(query(id << 1, l, r), query(id << 1 | 1, l, r));
}
} T;
inline void add_edge(int u, int v, int d)
{
++cnt;
e[cnt].to = v;
e[cnt].dis = d;
e[cnt].next = head[u];
head[u] = cnt;
}
inline int read()
{
int x = 0;
char ch = getchar();
while (ch > '9' || ch < '0')
ch = getchar();
while (ch <= '9' && ch >= '0')
x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
return x;
}
inline void dfs1(int u, int f)
{
size[u] = 1;
for (int i = head[u]; i; i = e[i].next)
{
int v = e[i].to;
if (v == f)
continue;
fa[v] = u;
dep[v] = dep[u] + 1;
a[v] = e[i].dis;
dfs1(v, u);
size[u] += size[v];
if (size[hson[u]] < size[v])
hson[u] = v;
}
}
inline void dfs2(int u, int Top)
{
++dfsnum;
dfn[u] = dfsnum;
pre[dfsnum] = u;
top[u] = Top;
if (hson[u])
dfs2(hson[u], Top);
for (int i = head[u]; i; i = e[i].next)
{
int v = e[i].to;
if (v == fa[u] || v == hson[u])
continue;
dfs2(v, v);
}
}
inline void modify(int pos, int val) { T.modify(1, dfn[pos], dfn[pos], val); }
inline int query_chain(int u, int v)
{
int ans = 0;
if (dfn[u] < dfn[v])
std::swap(u, v);
while (top[u] != top[v])
{
if (dfn[u] < dfn[v])
std::swap(u, v);
ans = std::max(ans, T.query(1, dfn[top[u]], dfn[u]));
u = fa[top[u]];
}
if (dfn[u] < dfn[v])
std::swap(u, v);
ans = std::max(ans, T.query(1, dfn[v] + 1, dfn[u]));
return ans;
}
int main()
{
n = read();
for (int i = 1; i < n; i++)
{
int u, v, d;
scanf("%d%d%d", &u, &v, &d);
from[i] = u;
to[i] = v;
add_edge(u, v, d);
add_edge(v, u, d);
}
dep[1] = 1, fa[1] = 0;
dfs1(1, 0), dfs2(1, 1);
T.build(1, 1, n);
std::string op;
std::cin >> op;
while (op != "DONE")
{
if (op == "CHANGE")
{
int x = read(), val = read();
int u = from[x], v = to[x];
if (fa[v] == u)
std::swap(u, v);
modify(u, val);
}
else
{
int a = read(), b = read();
printf("%d\n", query_chain(a, b));
}
std::cin >> op;
}
return 0;
}
Your browser is out-of-date!

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

×