传送门
求所有值在
l
∼
r
l \sim r
l∼r 区间的节点,距离某个点的距离和(有边权,也就是边权不一定为1,范围在1e9以内)
分析
这种要求
N
−
1
N-1
N−1个点到此某点的信息的问题,通常考虑使用【动态点分治】解决
对于每个作为重心的节点,维护他管辖范围内所有节点的距离,年龄信息,可以存入vector 中,在数组中按照年龄排序(原因是,查询要查找年龄区间的,这样才能二分找到),排序好后,求前缀和。最后统计的时候能够直接通过前缀和,得到区间内所有节点的距离和
同样,需要消除当前节点对父节点的影响,简单容斥
也就是,记录当前所有节点,如果对于父节点的查询来说,造成了多少影响,最后真正统计父节点的时候,将已经计算过的那一部分消去
代码,在luogu上,好像是vector的原因,导致不开O2后面那个点一直TLE,时限6s,差个(0.2s),开了O2,每个点1s左右
代码
//P3241
/*
@Author: YooQ
*/
#include <bits/stdc++.h>
using namespace std;
#define sc scanf
#define pr printf
#define ll long long
#define int long long
#define FILE_OUT freopen("out", "w", stdout);
#define FILE_IN freopen("in", "r", stdin);
#define debug(x) cout << #x << ": " << x << "\n";
#define AC 0
#define WA 1
#define INF 0x3f3f3f3f
const ll MAX_N = 3e5+5;
const ll MOD = 1e9+7;
int N, M, K;
int arr[MAX_N];
struct Node {
int k;
int sum;
Node(){
}
Node(int _k, int _sum) {
k = _k;
sum = _sum;
}
bool operator < (const Node& B) const {
return k < B.k;
}
};
int head[MAX_N];
int tot = 0;
struct Edge {
int to, nxt;
int w;
}edge[MAX_N<<1];
void addEdge(int u, int v, int w) {
edge[tot].nxt = head[u];
edge[tot].to = v;
edge[tot].w = w;
head[u] = tot++;
edge[tot].nxt = head[v];
edge[tot].to = u;
edge[tot].w = w;
head[v] = tot++;
}
int dep[MAX_N];
int len[MAX_N];
int top[MAX_N];
int son[MAX_N];
int sz[MAX_N];
int parent[MAX_N];
void dfs1(int u, int from, int k) {
parent[u] = from;
len[u] = k;
sz[u] = 1;
son[u] = 0;
dep[u] = dep[from] + 1;
int v;
for (int i = head[u];~i;i=edge[i].nxt) {
if ((v=edge[i].to) == from) continue;
dfs1(v, u, k + edge[i].w);
sz[u] += sz[v];
if (sz[v] > sz[son[u]]) {
son[u] = v;
}
}
}
void dfs2(int u, int tp) {
top[u] = tp;
if (son[u]) dfs2(son[u], tp);
int v;
for (int i = head[u];~i;i=edge[i].nxt) {
if ((v=edge[i].to) == son[u] || v == parent[u]) continue;
dfs2(v, v);
}
}
int LCA(int x, int y) {
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) swap(x, y);
x = parent[top[x]];
}
return dep[x] < dep[y] ? x : y;
}
int dis(int x, int y) {
int lca = LCA(x, y);
return len[x] + len[y] - len[lca] * 2;
}
bool vis[MAX_N];
int maxx[MAX_N];
int father[MAX_N];
int dsz[MAX_N];
void dfs(int u, int from, int& rt, int sum) {
sz[u] = 1;
maxx[u] = 0;
int v;
for (int i = head[u];~i;i=edge[i].nxt) {
if ((v=edge[i].to) == from || vis[v]) continue;
dfs(v, u, rt, sum);
sz[u] += sz[v];
maxx[u] = max(maxx[u], sz[v]);
}
maxx[u] = max(maxx[u], sum - sz[u]);
if (maxx[u] < maxx[rt]) {
rt = u;
}
}
vector<Node>A[MAX_N],B[MAX_N];
void save(int rt, int u, int from, int d) {
A[rt].push_back(Node(arr[u], d));
if (father[rt]) B[rt].push_back(Node(arr[u], dis(u, father[rt])));
int v;
for (int i = head[u];~i;i=edge[i].nxt) {
if ((v=edge[i].to) == from || vis[v]) continue;
save(rt, v, u, d + edge[i].w);
}
}
void divide(int u, int sum) {
vis[u] = 1;
dsz[u] = sum;
A[u].reserve(sum+1);
B[u].reserve(sum+1);
save(u, u, 0, 0);
int v;
for (int i = head[u];~i;i=edge[i].nxt) {
if (vis[v=edge[i].to]) continue;
int rt = 0;
int vsz = sz[u] > sz[v] ? sz[v] : sum - sz[u];
dfs(v, u, rt, vsz);
father[rt] = u;
divide(rt, vsz);
}
}
int calc(vector<Node>&vec, int l, int r, int fix) {
int st = lower_bound(vec.begin(), vec.end(), Node(l, -1)) - vec.begin() - 1;
int ed = upper_bound(vec.begin(), vec.end(), Node(r, -1)) - vec.begin() - 1;
int len = ed - st;
int res = 0;
if (ed >= 0 && ed < (int) vec.size()) res += vec[ed].sum;
if (st >= 0 && st < (int) vec.size()) res -= vec[st].sum;
return res += len * fix;
}
int count(int x, int l, int r) {
int res = 0, pre = 0;
int d;
for (int i = x; i; pre = i, i = father[i]) {
res += calc(A[i], l, r, d = dis(x, i));
if (pre) res -= calc(B[pre], l, r, d);
}
return res;
}
void init() {
memset(head, -1, sizeof head);
tot = 0;
}
void solve(){
init();
sc("%lld%lld%lld",&N, &M, &K);
int u, v, w;
for (int i = 1; i <= N; ++i) {
sc("%lld", &arr[i]);
}
for (int i = 1; i < N; ++i) {
sc("%lld%lld%lld", &u, &v, &w);
addEdge(u, v, w);
}
dfs1(1, 0, 0);
dfs2(1, 1);
int rt = 0;
maxx[rt] = 1e9;
dfs(1, 0, rt, N);
divide(rt, N);
for (int i = 1; i <= N; ++i) {
sort(A[i].begin(), A[i].end());
sort(B[i].begin(), B[i].end());
for (int j = 1; j < A[i].size(); ++j) {
A[i][j].sum += A[i][j-1].sum;
}
for (int j = 1; j < B[i].size(); ++j) {
B[i][j].sum += B[i][j-1].sum;
}
}
int a = 0, b = 0, pre = 0, l, r;
for (int i = 1; i <= M; ++i) {
sc("%lld%lld%lld", &u, &a, &b);
l = min((a+pre)%K, (b+pre)%K);
r = max((a+pre)%K, (b+pre)%K);
pr("%lld\n", pre = count(u, l, r));
}
}
signed main()
{
#ifndef ONLINE_JUDGE
FILE_IN
FILE_OUT
#endif
int T = 1;//cin >> T;
while (T--) solve();
return AC;
}