HYSBZ4012-开店

来源:互联网 发布:罗宾 知乎 编辑:程序博客网 时间:2024/04/23 20:04

[HNOI2015]开店

Time Limit: 70 Sec  Memory Limit: 512 MB
Submit: 1883  Solved: 811
[Submit][Status][Discuss]

Description

 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到

人生哲学。最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱。这样的
想法当然非常好啦,但是她们也发现她们面临着一个问题,那就是店开在哪里,面
向什么样的人群。很神奇的是,幻想乡的地图是一个树形结构,幻想乡一共有 n
个地方,编号为 1 到 n,被 n-1 条带权的边连接起来。每个地方都住着一个妖怪,
其中第 i 个地方的妖怪年龄是 x_i。妖怪都是些比较喜欢安静的家伙,所以它们并
不希望和很多妖怪相邻。所以这个树所有顶点的度数都小于或等于 3。妖怪和人一
样,兴趣点随着年龄的变化自然就会变化,比如我们的 18 岁少女幽香和八云紫就
比较喜欢可爱的东西。幽香通过研究发现,基本上妖怪的兴趣只跟年龄有关,所以
幽香打算选择一个地方 u(u为编号),然后在 u开一家面向年龄在 L到R 之间(即
年龄大于等于 L、小于等于 R)的妖怪的店。也有可能 u这个地方离这些妖怪比较
远,于是幽香就想要知道所有年龄在 L 到 R 之间的妖怪,到点 u 的距离的和是多
少(妖怪到 u 的距离是该妖怪所在地方到 u 的路径上的边的权之和) ,幽香把这个
称为这个开店方案的方便值。幽香她们还没有决定要把店开在哪里,八云紫倒是准
备了很多方案,于是幽香想要知道,对于每个方案,方便值是多少呢。

Input

 第一行三个用空格分开的数 n、Q和A,表示树的大小、开店的方案个数和妖

怪的年龄上限。 
第二行n个用空格分开的数 x_1、x_2、…、x_n,x_i 表示第i 个地点妖怪的年
龄,满足0<=x_i<A。(年龄是可以为 0的,例如刚出生的妖怪的年龄为 0。) 
接下来 n-1 行,每行三个用空格分开的数 a、b、c,表示树上的顶点 a 和 b 之
间有一条权为c(1 <= c <= 1000)的边,a和b 是顶点编号。 
接下来Q行,每行三个用空格分开的数 u、 a、 b。对于这 Q行的每一行,用 a、
b、A计算出 L和R,表示询问“在地方 u开店,面向妖怪的年龄区间为[L,R]的方
案的方便值是多少”。对于其中第 1 行,L 和 R 的计算方法为:L=min(a%A,b%A), 
R=max(a%A,b%A)。对于第 2到第 Q行,假设前一行得到的方便值为 ans,那么当
前行的 L 和 R 计算方法为: L=min((a+ans)%A,(b+ans)%A), 
R=max((a+ans)%A,(b+ans)%A)。 

Output

对于每个方案,输出一行表示方便值。 

Sample Input

10 10 10
0 0 7 2 1 4 7 7 7 9
1 2 270
2 3 217
1 4 326
2 5 361
4 6 116
3 7 38
1 8 800
6 9 210
7 10 278
8 9 8
2 8 0
9 3 1
8 0 8
4 2 7
9 7 3
4 7 0
2 2 7
3 2 1
2 3 4

Sample Output

1603
957
7161
9466
3232
5223
1879
1669
1282
0

HINT

 满足 n<=150000,Q<=200000。对于所有数据,满足 A<=10^9

Source


解题思路:树分治


#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <algorithm>#include <cmath>#include <map>#include <set>#include <stack>#include <queue>#include <vector>#include <bitset>#include <functional>using namespace std;#define LL long longconst int INF = 0x3f3f3f3f;const int maxn = 3e5 + 10;int n, q, A, a[maxn];int s[maxn], nt[maxn], e[maxn], v[maxn], cnt;int mx[maxn], ct[maxn], vis[maxn];int pre[maxn], nt1[maxn][3];struct node{int x, y;node(int x = 0, int y = 0) :x(x), y(y) {}bool operator < (const node &a)const{return x < a.x;}};vector<node> t[maxn][3], dis[maxn];vector<LL> x[maxn][3];int dfs(int k, int fa, int sum){int ans = mx[k] = (ct[k] = 1) - 1;for (int i = s[k]; ~i; i = nt[i]){if (e[i] == fa || vis[e[i]]) continue;int y = dfs(e[i], k, sum);ct[k] += ct[e[i]];mx[k] = max(mx[k], ct[e[i]]);ans = mx[ans] < mx[y] ? ans : y;}mx[k] = max(mx[k], sum - ct[k]);return mx[k] < mx[ans] ? k : ans;}void Find(int k, int fa, int rt, int id, int len){dis[rt].push_back(node(k, len));t[rt][id].push_back(node(a[k], len));for (int i = s[k]; ~i; i = nt[i]){if (vis[e[i]] || e[i] == fa) continue;Find(e[i], k, rt, id, len + v[i]);}}int build(int k, int sum, int fa){int y = dfs(k, k, sum);pre[y] = fa, vis[y] = 1;int id = 0;dis[y].push_back(node(y, 0));for (int i = s[y]; i != -1; i = nt[i], id++){if (vis[e[i]]) continue;Find(e[i], y, y, id, v[i]);sort(t[y][id].begin(), t[y][id].end());for (LL j = 0, k = 0; j < t[y][id].size(); j++){k += t[y][id][j].y;x[y][id].push_back(k);}nt1[y][id] = build(e[i], ct[e[i]] > ct[y] ? sum - ct[y] : ct[e[i]], y);}sort(dis[y].begin(), dis[y].end());return y;}LL solve(int rt, int k, int l, int r, int from){if (k == -1) return 0;LL ans = 0, sum = 0;for (int i = 0; i < 3; i++){if (i == from || t[k][i].empty()) continue;int L = lower_bound(t[k][i].begin(), t[k][i].end(), node(l, 0)) - t[k][i].begin();int R = upper_bound(t[k][i].begin(), t[k][i].end(), node(r, 0)) - t[k][i].begin();ans += (R ? x[k][i][R - 1] : 0) - (L ? x[k][i][L - 1] : 0);sum += R - L;}int d = dis[k][lower_bound(dis[k].begin(), dis[k].end(), node(rt, 0)) - dis[k].begin()].y;ans = ans + (sum + (a[k] >= l&&a[k] <= r))*d;for (int i = 0; i < 3; i++)if (pre[k] != -1 && nt1[pre[k]][i] == k) from = i;return ans + solve(rt, pre[k], l, r, from);}int main(){while (~scanf("%d%d%d", &n, &q, &A)){mx[cnt = 0] = INF;for (int i = 1; i <= n; i++){s[i] = -1; vis[i] = 0;dis[i].clear();for (int j = 0; j < 3; j++){t[i][j].clear();x[i][j].clear();nt1[i][j] = 0;}}for (int i = 1; i <= n; i++) scanf("%d", &a[i]);for (int i = 1; i < n; i++){int uu, vv, ww;scanf("%d%d%d", &uu, &vv, &ww);nt[cnt] = s[uu], s[uu] = cnt, e[cnt] = vv, v[cnt++] = ww;nt[cnt] = s[vv], s[vv] = cnt, e[cnt] = uu, v[cnt++] = ww;}build(1, n, -1);LL ans = 0;while (q--){int u, l, r, ll, rr;scanf("%d%d%d", &u, &l, &r);ll = min((ans + l) % A, (ans + r) % A);rr = max((ans + l) % A, (ans + r) % A);ans = solve(u, u, ll, rr, -1);printf("%lld\n", ans);}}return 0;}