题目
样例输入
5
7 7 6 9 9
2 5 5
2 3 1
4 1 1
1 2 2
4
2
5
3
4
样例输出
1
7
0
3
题解
- 对于一条链的情况:
- 假设我们当前要求的点为 u u u,那么我们可以建一棵线段树,树上每个节点 v v v表示 − c [ v ] + d i s ( u , v ) -c[v]+dis(u,v) −c[v]+dis(u,v),在我们进行区间修改时,假设我们要更新的下一个点为 u ′ u' u′,我们只需将这个点右边的点的权值减去 d i s ( u , u ′ ) dis(u,u') dis(u,u′),左边的点的权值加上 d i s ( u ′ u ) dis(u'u) dis(u′u)即可(画个图应该很好理解吧)
- 询问时只需询问 1 1 1~ n n n中的最小值即可(不包括询问点的最小值)
- 对于树的情况
- 对于修改操作我们只需修改它子树内和子树外的范围,而判断这个范围我们可以借助 d f s dfs dfs序。
- 注意
- 我们用 d f s dfs dfs序时相当于将整个树重新编号,询问时要注意用该点的新编号
- 子树外具体范围不好表示,故我们可以先将整棵树整体赋值,然后在处理子树内的部分
- 在询问答案时,我将所有答案预处理出来,采用树的遍历的方式进行更新(因为想不到其他更新方式)
code
#include <bits/stdc++.h>
using namespace std;
const int maxn = 3e5 + 1000;
typedef long long LL;
template <typename T>
inline void read(T &s) {
s = 0;
T w = 1, ch = getchar();
while (!isdigit(ch)) { if (ch == '-') w = -1; ch = getchar(); }
while (isdigit(ch)) { s = (s << 1) + (s << 3) + (ch ^ 48); ch = getchar(); }
s *= w;
}
int n, q, tot, cnt;
int c[maxn], f[maxn], d[maxn];
int dfn[maxn], siz[maxn], lin[maxn], pre[maxn];
LL ans[maxn];
int num = 0;
struct node {
int next, to, dis;
} e[maxn * 2];
struct tree {
int l, r;
LL dat, add;
} t[maxn * 4];
inline void add(int from, int to, int dis) {
e[++tot].to = to;
e[tot].dis = dis;
e[tot].next = lin[from];
lin[from] = tot;
}
void dfs(int u, int fa) {
siz[u] = 1;
dfn[u] = ++cnt;
pre[cnt] = u;
for (int i = lin[u]; i; i = e[i].next) {
int v = e[i].to;
if (v == fa) continue;
d[v] = d[u] + e[i].dis;
dfs(v, u);
siz[u] += siz[v];
}
}
void build(int p, int l, int r) {
t[p].l = l, t[p].r = r;
if (l == r) {
t[p].dat = d[pre[l]] - c[pre[l]];
return ;
}
int mid = (l + r) >> 1;
build(p<<1, l, mid);
build(p<<1|1, mid + 1, r);
t[p].dat = min(t[p<<1].dat, t[p<<1|1].dat);
}
void spread(int p) {
t[p<<1].dat += t[p].add;
t[p<<1|1].dat += t[p].add;
t[p<<1].add += t[p].add;
t[p<<1|1].add += t[p].add;
t[p].add = 0;
}
void change(int p, int l, int r, int v) {
if (l <= t[p].l && r >= t[p].r) {
t[p].dat += 1ll * v;
t[p].add += 1ll * v;
return ;
}
spread(p);
int mid = (t[p].l + t[p].r) >> 1;
if (l <= mid) change(p<<1, l, r, v);
if (r > mid) change(p<<1|1, l, r, v);
t[p].dat = min(t[p<<1].dat, t[p<<1|1].dat);
}
LL query(int p, int l, int r) {
if (l <= t[p].l && r >= t[p].r) return t[p].dat;
spread(p);
int mid = (t[p].l + t[p].r) >> 1;
LL val = 0x3f3f3f3f;
if (l <= mid) val = min(val, query(p<<1, l, r));
if (r > mid) val = min(val, query(p<<1|1, l, r));
return val;
}
void work(int u, int fa) {
for (int i = lin[u]; i; i = e[i].next) {
int v = e[i].to;
if (v == fa) continue;
int dd = e[i].dis;
change(1, 1, n, dd);
change(1, dfn[v], dfn[v] + siz[v] - 1, -2 * dd);
LL res = 0x3f3f3f3f;
if (dfn[v] > 1)
res = min(res, query(1, 1, dfn[v] - 1));
if (dfn[v] < n)
res = min(res, query(1, dfn[v] + 1, n));
ans[v] = res + 1ll * c[v];
work(v, u);
change(1, 1, n, -dd);
change(1, dfn[v], dfn[v] + siz[v] - 1, 2 * dd);
}
}
signed main() {
// freopen("skylines.in", "r", stdin);
// freopen("skylines.out", "w", stdout);
freopen("1.in", "r", stdin);
freopen("1.out", "w", stdout);
read(n);
for (int i = 1; i <= n; ++i) read(c[i]);
for (int i = 1; i < n; ++i) {
int x, y, z;
read(x), read(y), read(z);
add(x, y, z);
add(y, x, z);
}
d[1] = 0;
dfs(1, 0);
build(1, 1, n);
ans[1] = 1ll * query(1, 2, n) + c[1];
work(1, 0);
read(q);
for (int i = 1; i <= q; ++i) {
int x; read(x);
printf("%lld\n", ans[x]);
}
return 0;
}
/*
5
7 7 6 9 9
2 5 5
2 3 1
4 1 1
1 2 2
4
2
5
3
4
*/
/*
5
7 7 6 9 9
2 5 5
2 3 1
4 1 1
1 2 2
1
5
*/