题意:
给一棵树,每个点上有点权,边上有边权。
每次询问一个u,l,r,输出点权在[l,r]范围内的点到u的距离和。
强制在线。
做法:
考虑一棵树上所有点到一个点的距离和怎么求。
不难发现应该等于所有点的深度和+点数×u的深度-2×所有点与u的lca的深度和。
于是问题就在于求所有点与u的lca的深度和。
对于这个问题,我们可以先把每个点到根的路径都打标记,然后查询的时候就是查询u-根的边权×标记数。
可以用树链剖分+线段树实现。
然后题目还有一个要求是点权在[l,r]范围内。
所以就加一个可持久化,把点按照点权从小到大排序,每次的满足要求的点就是区间上连续一段,每种点权上建一棵线段树维护一下即可。
代码:
/*************************************************************
Problem: bzoj 4012 [HNOI2015]开店
User: fengyuan
Language: C++
Result: Accepted
Time: 17172 ms
Memory: 484268 kb
Submit_Time: 2018-01-08 18:47:16
*************************************************************/
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cctype>
#include<cmath>
#define mid (l+r>>1)
using namespace std;
typedef long long LL;
inline LL read()
{
char ch = getchar(); LL x = 0; int op = 1;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') op = -1;
for(; isdigit(ch); ch = getchar()) x = x*10 + ch-'0';
return x*op;
}
inline void write(LL a) { if(a < 0) putchar('-'), a = -a; if(a >= 10) write(a/10); putchar(a%10+'0'); }
const int N = 150010, M = 20000010;
int n, q, m, cnt, clk, all;
int head[N], num[N], p[N], last[N], in[N], depth[N], sz[N], fa[N], son[N], top[N], rt[N], L[M], R[M];
LL sum[M], times[M], sum_edge[N], sum_dep[N];
struct Node{
int val, id;
Node() {}
Node(int x, int y) { val = x, id = y; }
}a[N];
struct Edge{
int to, nxt, v;
Edge() {}
Edge(int x, int y, int z) { to = x, nxt = y, v = z; }
}e[N<<1];
bool operator < (Node x, Node y) { return x.val < y.val || x.val == y.val && x.id < y.id; }
inline void addEdge(int x, int y, int z) { e[++ cnt] = Edge(y, head[x], z); head[x] = cnt; }
const bool cmp(const Node &x, const Node &y) { return x.val < y.val; }
inline void dfs(int u, int lst, int s)
{
depth[u] = s; fa[u] = lst; sz[u] = 1;
for(int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to; if(v == lst) continue;
dfs(v, u, s+e[i].v); last[v] = e[i].v; sz[u] += sz[v];
if(!son[u] || sz[v] > sz[son[u]]) son[u] = v;
}
}
inline void dfs2(int u, int t)
{
in[u] = ++ clk; sum_edge[clk] = last[u]; top[u] = t;
if(son[u]) dfs2(son[u], t);
for(int i = head[u]; i; i = e[i].nxt) if(e[i].to != fa[u] && e[i].to != son[u]) dfs2(e[i].to, e[i].to);
}
inline void add(int pre, int &rt, int l, int r, int x, int y)
{
rt = ++ all; sum[rt] = sum[pre]; times[rt] = times[pre]; L[rt] = L[pre]; R[rt] = R[pre];
if(l == x && r == y) { times[rt] ++; return; }
sum[rt] += sum_edge[y] - sum_edge[x-1];
if(y <= mid) add(L[pre], L[rt], l, mid, x, y);
else if(x > mid) add(R[pre], R[rt], mid+1, r, x, y);
else add(L[pre], L[rt], l, mid, x, mid), add(R[pre], R[rt], mid+1, r, mid+1, y);
}
inline LL query(int rt, int l, int r, int x, int y)
{
LL ret = 1LL*times[rt]*(sum_edge[y]-sum_edge[x-1]);
if(l == x && r == y) return ret + sum[rt];
if(y <= mid) return ret + query(L[rt], l, mid, x, y);
else if(x > mid) return ret + query(R[rt], mid+1, r, x, y);
else return ret + query(L[rt], l, mid, x, mid) + query(R[rt], mid+1, r, mid+1, y);
}
inline void modify(int t, int x)
{
while(top[x] != 1) { add(rt[t], rt[t], 1, n, in[top[x]], in[x]); x = fa[top[x]]; }
add(rt[t], rt[t], 1, n, 1, in[x]);
}
inline LL getsum(int t, int x)
{
LL ret = 0;
while(top[x] != 1) { ret += query(rt[t], 1, n, in[top[x]], in[x]); x = fa[top[x]]; }
return ret + query(rt[t] , 1, n, 1, in[x]);
}
int main()
{
n = read(), q = read(), m = read();
for(int i = 1; i <= n; i ++) a[i].val = read(), a[i].id = i;
sort(a+1, a+1+n);
for(int i = 1; i < n; i ++) {
int x = read(), y = read(), z = read();
addEdge(x, y, z); addEdge(y, x, z);
}
dfs(1, 0, 0); dfs2(1, 1);
for(int i = 1; i <= n; i ++) { sum_edge[i] += sum_edge[i-1]; sum_dep[i] = sum_dep[i-1]+depth[a[i].id]; }
for(int i = 1; i <= n; i ++) { rt[i] = rt[i-1]; modify(i, a[i].id); }
LL lastans = 0;
while(q --) {
int x = read(), l = (read()+lastans)%m, r = (read()+lastans)%m;
if(l > r) swap(l, r); Node ll, rr; ll = Node(l, 0), rr = Node(r, 1e9);
l = lower_bound(a+1, a+1+n, ll)-a;
r = upper_bound(a+1, a+1+n, rr)-a-1;
lastans = 1LL*(r-l+1)*depth[x] + sum_dep[r]-sum_dep[l-1]-2LL*(getsum(r, x)-getsum(l-1, x));
write(lastans), puts("");
}
return 0;
}