传送门:BZOJ-4012
题意:给定一棵树,每个点有一个颜色,多次询问颜色在[l,r]区间内的所有点与某个点之间的距离之和
又是一个数组开小T到怀疑人生系列。。(我怎么总是管不住这双手root数组只开MX呢)
一个经典的动态树分治题目,用树状数组保存每种颜色的节点到该层子树的根节点的距离,然后一层一层计算就行。
= =本来应该是这样的,后来看了下发现颜色有n种,n^2logn的树状数组肯定爆内存啊。
后来想了下,明明只要记录区间内的值,用个vector弄下前缀和不就行了吗。。。(哈希都省去了
#include<cstdio>
#include<string.h>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int MX = 150005;
const int MXM = MX * 40;
const int inf = 0x3f3f3f3f;
struct Edge {
int v, w, nxt;
} E[MX * 2];
int head[MX], tot;
struct node {
int rt, subrt, nxt;
LL dis;
} root[MXM];
struct p {
int x;
LL y, cnt;
p(int x = 0, LL y = 0, LL cnt = 0): x(x), y(y), cnt(cnt) {}
bool operator<(const p& _A)const {
return x < _A.x;
}
};
int fir[MX], rear;
int a[MX], vis[MX], sz[MX], id[MX];
int n, Root, Maxv, cnt;
vector<p>T[MX << 2], tmp;
void init() {
memset(head, -1, sizeof(head));
memset(fir, -1, sizeof(fir));
memset(vis, 0, sizeof(vis));
tot = rear = cnt = 0;
}
void add_edge(int u, int v, int w) {
E[tot].v = v;
E[tot].w = w;
E[tot].nxt = head[u];
head[u] = tot++;
}
void add_root(int u, int rt, int subrt, LL dis) {
root[rear].rt = rt;
root[rear].subrt = subrt;
root[rear].dis = dis;
root[rear].nxt = fir[u];
fir[u] = rear++;
}
void dfs_size(int u, int fa) {
sz[u] = 1;
for (int i = head[u]; ~i; i = E[i].nxt) {
int v = E[i].v;
if (vis[v] || v == fa) continue;
dfs_size(v, u);
sz[u] += sz[v];
}
}
void dfs_root(int u, int fa, int rt) {
if (max(sz[u], sz[rt] - sz[u]) < Maxv) {
Maxv = max(sz[u], sz[rt] - sz[u]);
Root = u;
}
for (int i = head[u]; ~i; i = E[i].nxt) {
int v = E[i].v;
if (vis[v] || v == fa) continue;
dfs_root(v, u, rt);
}
}
p arr[MX];
void cal(int u) {
if (T[u].empty()) return;
sort(T[u].begin(), T[u].end());
int sz = 0;
arr[++sz] = p(-1, 0, 0);
for (int i = 0; i < T[u].size(); i++) {
if (T[u][i].x != arr[sz].x) {
arr[++sz].x = T[u][i].x;
arr[sz].y = arr[sz - 1].y + T[u][i].y;
arr[sz].cnt = arr[sz - 1].cnt + 1;
} else {
arr[sz].y += T[u][i].y;
arr[sz].cnt++;
}
}
T[u].resize(sz);
for (int i = 1; i <= sz; i++) T[u][i - 1] = arr[i];
}
void dfs_tree(int u, int fa, int rt, int subrt, LL dir) {
add_root(u, rt, subrt, dir);
T[rt].push_back(p(a[u], dir, 1));
T[subrt].push_back(p(a[u], dir, 1));
for (int i = head[u]; ~i; i = E[i].nxt) {
int v = E[i].v;
if (vis[v] || v == fa) continue;
dfs_tree(v, u, rt, subrt, dir + E[i].w);
}
}
void dfs(int u) {
Root = 0; Maxv = n;
dfs_size(u, -1); dfs_root(u, -1, u);
vis[Root] = 1; id[Root] = ++cnt;
T[cnt].clear();
T[cnt].push_back(p(a[Root], 0, 1));
add_root(Root, id[Root], 0, 0);
for (int i = head[Root]; ~i; i = E[i].nxt) {
int v = E[i].v;
if (vis[v]) continue;
T[++cnt].clear();
dfs_tree(v, Root, id[Root], cnt, E[i].w);
cal(cnt);
}
cal(id[Root]);
for (int i = head[Root]; ~i; i = E[i].nxt) {
int v = E[i].v;
if (vis[v]) continue;
dfs(v);
}
}
p Query(int rt, int l, int r) {
if (T[rt].empty()) return p();
int p1 = lower_bound(T[rt].begin(), T[rt].end(), p(l)) - T[rt].begin() - 1;
int p2 = upper_bound(T[rt].begin(), T[rt].end(), p(r)) - T[rt].begin() - 1;
return p(0, T[rt][p2].y - T[rt][p1].y, T[rt][p2].cnt - T[rt][p1].cnt);
}
LL query(int u, int l, int r) {
LL ret = 0;
for (int i = fir[u]; ~i; i = root[i].nxt) {
int rt = root[i].rt, subrt = root[i].subrt, dis = root[i].dis;
p p1 = Query(rt, l, r);
p p2 = Query(subrt, l, r);
ret += p1.y - p2.y + (p1.cnt - p2.cnt) * dis;
}
return ret;
}
int main() {
int m, A;
//freopen("in.txt", "r", stdin);
scanf("%d%d%d", &n, &m, &A);
init();
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
for (int i = 1, u, v, w; i < n; i++) {
scanf("%d%d%d", &u, &v, &w);
add_edge(u, v, w); add_edge(v, u, w);
}
dfs(1);
LL ans = 0;
for (int i = 1, u, l, r; i <= m; i++) {
scanf("%d%d%d", &u, &l, &r);
l = (l + ans) % A;
r = (r + ans) % A;
if (l > r) swap(l, r);
printf("%lld\n", ans = query(u, l, r));
}
return 0;
}