Description
风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到
人生哲学。最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱。这样的
想法当然非常好啦,但是她们也发现她们面临着一个问题,那就是店开在哪里,面
向什么样的人群。很神奇的是,幻想乡的地图是一个树形结构,幻想乡一共有 n
个地方,编号为 1 到 n,被 n-1 条带权的边连接起来。每个地方都住着一个妖怪,
其中第 i 个地方的妖怪年龄是 x_i。妖怪都是些比较喜欢安静的家伙,所以它们并
不希望和很多妖怪相邻。所以这个树所有顶点的度数都小于或等于 3。妖怪和人一
样,兴趣点随着年龄的变化自然就会变化,比如我们的 18 岁少女幽香和八云紫就
比较喜欢可爱的东西。幽香通过研究发现,基本上妖怪的兴趣只跟年龄有关,所以
幽香打算选择一个地方 u(u为编号),然后在 u开一家面向年龄在 L到R 之间(即
年龄大于等于 L、小于等于 R)的妖怪的店。也有可能 u这个地方离这些妖怪比较
远,于是幽香就想要知道所有年龄在 L 到 R 之间的妖怪,到点 u 的距离的和是多
少(妖怪到 u 的距离是该妖怪所在地方到 u 的路径上的边的权之和) ,幽香把这个
称为这个开店方案的方便值。幽香她们还没有决定要把店开在哪里,八云紫倒是准
备了很多方案,于是幽香想要知道,对于每个方案,方便值是多少呢。
Solution
我们将答案变成
1
…
R
1\dots R
1…R的答案减去
1
…
L
−
1
1\dots L-1
1…L−1的答案,于是我们询问的点集变成了一个前缀和。
设询问的点集为
S
S
S,
d
e
p
[
u
]
dep[u]
dep[u]表示
u
u
u到根的距离,那么答案为:
∑
v
∈
S
d
i
s
(
u
,
v
)
=
∑
v
∈
S
d
e
p
[
v
]
+
∣
S
∣
×
d
e
p
[
u
]
+
2
×
∑
v
∈
S
d
e
p
[
L
C
A
(
u
,
v
)
]
\sum _{v\in S} dis(u,v) = \sum_{v\in S}dep[v] + |S|\times dep[u] + 2\times \sum_{v\in S}dep[LCA(u, v)]
v∈S∑dis(u,v)=v∈S∑dep[v]+∣S∣×dep[u]+2×v∈S∑dep[LCA(u,v)]
关于求
∑
v
∈
S
d
e
p
[
L
C
A
(
u
,
v
)
]
\sum_{v\in S}dep[LCA(u, v)]
∑v∈Sdep[LCA(u,v)],在LNOI2014 LCA这题中,我们有一个离线做法,就是将点集中的点依次加入,将其到根路径上的点全部加一,询问
u
u
u到根路径上的权值和即为答案。
LNOI2014LCA是允许离线的。如果要求在线,我们用主席树搞即可。由于要资瓷区间加,所以要搞一个标记永久化。
Code
/************************************************
* Au: Hany01
* Date: Sep 12th, 2018
* Prob: BZOJ4012 HNOI2015 开店
* Email: hany01dxx@gmail.com & hany01@foxmail.com
* Inst: Yali High School
************************************************/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long double LD;
typedef pair<int, int> PII;
#define rep(i, j) for (register int i = 0, i##_end_ = (j); i < i##_end_; ++ i)
#define For(i, j, k) for (register int i = (j), i##_end_ = (k); i <= i##_end_; ++ i)
#define Fordown(i, j, k) for (register int i = (j), i##_end_ = (k); i >= i##_end_; -- i)
#define Set(a, b) memset(a, b, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define x first
#define y second
#define pb(a) push_back(a)
#define mp(a, b) make_pair(a, b)
#define SZ(a) ((int)(a).size())
#define ALL(a) a.begin(), a.end()
#define INF (0x3f3f3f3f)
#define INF1 (2139062143)
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define y1 wozenmezhemecaia
template <typename T> inline bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }
template <typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }
inline int read() {
static int _, __; static char c_;
for (_ = 0, __ = 1, c_ = getchar(); c_ < '0' || c_ > '9'; c_ = getchar()) if (c_ == '-') __ = -1;
for ( ; c_ >= '0' && c_ <= '9'; c_ = getchar()) _ = (_ << 1) + (_ << 3) + (c_ ^ 48);
return _ * __;
}
const int maxn = 15e4 + 5, maxm = 3e5 + 5;
int n, q, MOD, ls[maxn], lss, beg[maxn], nex[maxm], v[maxm], w[maxm], e = 1, W[maxn], dep[maxn], sz[maxn], fa[maxn], top[maxn], son[maxn], dfn[maxn], rt[maxn], clk, cnt[maxn];
LL diss[maxn], dis[maxn], sumW[maxn];
PII node[maxn];
inline void add(int uu, int vv, int ww) { v[++ e] = vv, w[e] = ww, nex[e] = beg[uu], beg[uu] = e; }
void DFS1(int u, int pa) {
dep[u] = dep[fa[u] = pa] + 1, sz[u] = 1;
for (register int i = beg[u]; i; i = nex[i]) if (v[i] != pa)
dis[v[i]] = dis[u] + (W[v[i]] = w[i]), DFS1(v[i], u), sz[u] += sz[v[i]], son[u] = sz[son[u]] < sz[v[i]] ? v[i] : son[u];
}
void DFS2(int u) {
dfn[u] = ++ clk, sumW[clk] = sumW[clk - 1] + W[u];
if (son[u]) top[son[u]] = top[u], DFS2(son[u]);
for (register int i = beg[u]; i; i = nex[i])
if (v[i] != fa[u] && v[i] != son[u]) top[v[i]] = v[i], DFS2(v[i]);
}
struct SegmentTree {
#define mid ((l + r) >> 1)
int tot;
struct Node { int lc, rc, tag; LL sum; } tr[maxn * 55];
void update(int &t, int las, int l, int r, int x, int y) {
tr[t = ++ tot] = tr[las], tr[t].sum += sumW[min(r, y)] - sumW[max(l, x) - 1];
if (x <= l && r <= y) { ++ tr[t].tag; return; }
if (x <= mid) update(tr[t].lc, tr[las].lc, l, mid, x, y);
if (y > mid) update(tr[t].rc, tr[las].rc, mid + 1, r, x, y);
}
LL query(int t, int l, int r, int x, int y, int tags) {
if (x <= l && r <= y) return tr[t].sum + (LL)tags * (sumW[r] - sumW[l - 1]);
tags += tr[t].tag;
if (y <= mid) return query(tr[t].lc, l, mid, x, y, tags);
if (x > mid) return query(tr[t].rc, mid + 1, r, x, y, tags);
return query(tr[t].lc, l, mid, x, y, tags) + query(tr[t].rc, mid + 1, r, x, y, tags);
}
}ST;
inline void insert(int i, int u) {
for (; top[u] != 1; u = fa[top[u]]) ST.update(rt[i], rt[i], 1, n, dfn[top[u]], dfn[u]);
ST.update(rt[i], rt[i], 1, n, 1, dfn[u]);
}
inline LL ask(int t1, int t2, int u) {
LL ans = 0;
for (; top[u] != 1; u = fa[top[u]])
ans += ST.query(t2, 1, n, dfn[top[u]], dfn[u], 0) - ST.query(t1, 1, n, dfn[top[u]], dfn[u], 0);
return ans + ST.query(t2, 1, n, 1, dfn[u], 0) - ST.query(t1, 1, n, 1, dfn[u], 0);
}
int main()
{
#ifdef hany01
freopen("bzoj4012.in", "r", stdin);
freopen("bzoj4012.out", "w", stdout);
#endif
static int uu, vv, ww, cur, l, r, u;
static LL ans;
n = read(), q = read(), MOD = read();
For(i, 1, n) node[i] = mp(ls[i] = read(), i);
sort(ls + 1, ls + 1 + n), lss = unique(ls + 1, ls + 1 + n) - ls - 1;
For(i, 1, n) node[i].x = lower_bound(ls + 1, ls + 1 + lss, node[i].x) - ls;
For(i, 2, n) uu = read(), vv = read(), ww = read(), add(uu, vv, ww), add(vv, uu, ww);
DFS1(1, 0), top[1] = 1, DFS2(1);
sort(node + 1, node + 1 + n);
For(i, 1, lss)
for (rt[i] = rt[i - 1], diss[i] = diss[i - 1], cnt[i] = cnt[i - 1]; cur < n && node[cur + 1].x <= i; )
insert(i, node[++ cur].y), diss[i] += dis[node[cur].y], ++ cnt[i];
while (q --) {
u = read(), l = (read() + ans % MOD) % MOD, r = (read() + ans % MOD) % MOD;
if (l > r) swap(l, r);
l = lower_bound(ls + 1, ls + 1 + lss, l) - ls, r = upper_bound(ls + 1, ls + 1 + lss, r) - ls - 1;
printf("%lld\n", ans = (diss[r] - diss[l - 1] + (LL)dis[u] * (cnt[r] - cnt[l - 1]) - ask(rt[l - 1], rt[r], u) * 2));
}
return 0;
}