[HNOI2015]开店
Time Limit: 70 Sec Memory Limit: 512 MBSubmit: 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
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
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 long
const 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;
}