您的位置:首页 > 其它

BZOJ 4012 HNOI 2015 开店 动态点分治

2016-04-03 00:10 459 查看
多次询问给定点到点权在[l,r]间的所有点距离之和。

询问某个点x到其他点的距离之和,可以考虑其到根的路径上的点,发现其和可以表示为(为了简单表示,令c[x]表示x所在子树内的所有点)

c[x]到x的距离和+

{c[fa[x]]-c[x]}到fa[x]的距离和+|{c[fa[x]]-c[x]}|*dis(x,fa[x])+

….

c[fa[x]]-c[x]表示x的父亲的子树的所有点除了x子树内的所有点。

由于我们始终关心的是:一个点的子树;而不关心点间路径;意味着我们可以重构树结构。

点分治满足计算上面数据的要求,按重心构造新树再上面做文章即可。

为每个点维护其在新树上子树中各点到其距离,以及从父亲经过该点到子树中各点的距离。

而点权范围前缀和二分即可。

#include <vector>
#include <cstdio>
#include <algorithm>
#define FOR(i,j,k) for(i=j;i<=k;++i)
const int N = 150005, M = N * 2, inf = 2147483647, K = 19;
typedef long long ll;
using namespace std;
struct Data { ll a, b; Data() {} Data(ll c, ll d) : a(c), b(d) {} };
typedef vector<Data> Collection;
bool operator< (const Data &a, const Data &b) { return a.a == b.a ? a.b < b.b : a.a < b.a; }
Data operator- (const Data &a, const Data &b) { return Data(a.a - b.a, a.b - b.b); }
int a
;
Collection s1
, s2
;
int vis[M], p[M], v[M], h
, w[M], cnt = 1, node, rt;
int lb[M], dep
, dis
, g
, sz
, fa[M], lf[M][20];
void add(int a, int b, int c) {
p[++cnt] = h[a]; v[cnt] = b; w[cnt] = c; h[a] = cnt;
}
void root(int x, int fa) {
sz[x] = 1; g[x] = 0;
for (int i = h[x]; i; i = p[i])
if (v[i] != fa && !vis[i]) {
root(v[i], x);
sz[x] += sz[v[i]];
g[x] = max(g[x], sz[v[i]]);
}
g[x] = max(g[x], node - sz[x]);
if (g[x] < g[rt]) rt = x;
}
int get_root(int x, int fa, int sz) {
rt = 0; node = sz; g[0] = inf;
root(x, fa); return rt;
}
void dfs_seq(int x, int fa, int dep, Collection &s) {
s.push_back(Data(a[x], dep));
for (int i = h[x]; i; i = p[i])
if (!vis[i] && v[i] != fa)
dfs_seq(v[i], x, dep + w[i], s);
}
void work(int x) {
dfs_seq(x, 0, 0, s1[x]);
for (int i = h[x]; i; i = p[i])
if (!vis[i]) {
vis[i] = vis[i ^ 1] = true;
int cg = get_root(v[i], x, sz[v[i]]);
dfs_seq(v[i], 0, w[i], s2[cg]);
fa[cg] = x;
work(cg);
}
}
void process(Collection &c) {
c.push_back(Data(-1, 0));
sort(c.begin(), c.end());
for (int i = 1; i < c.size(); ++i)
c[i].b += c[i - 1].b;
}
void dfs(int x, int fa) {
int i;
dep[x] = dep[lf[x][0] = fa] + 1;
FOR(i,1,K) lf[x][i] = lf[lf[x][i - 1]][i - 1];
for (i = h[x]; i; i = p[i])
if (v[i] != fa) {
dis[v[i]] = dis[x] + w[i];
dfs(v[i], x);
}
}
int lca(int x, int y) {
if (dep[x] < dep[y]) swap(x, y);
int t = dep[x] - dep[y], i;
FOR(i,0,K) if ((1 << i) & t) x = lf[x][i];
for(i=K;i>=0;--i) if (lf[x][i] != lf[y][i]) x = lf[x][i], y = lf[y][i];
return x == y ? x : lf[x][0];
}
int dist(int a, int b) {
return dis[a] + dis[b] - 2 * dis[lca(a, b)];
}
Data query(Collection &a, int l, int r) {
if (a.empty()) return Data(0, 0);
Collection::iterator i = lower_bound(a.begin(), a.end(), Data(l, 0)),
j = lower_bound(a.begin(), a.end(), Data(r + 1, 0));
--i; --j;
return Data(j->b - i->b, j - i);
}
int main() {
int i, j, n, m; ll x, y, z, p, ans = 0;
scanf("%d%d%lld", &n, &m, &p);
FOR(i,1,n) scanf("%d", a + i);
FOR(i,2,n) scanf("%lld%lld%lld", &x, &y, &z), add(x, y, z), add(y, x, z);
work(get_root(1, 0, n));
FOR(i,1,n) process(s1[i]), process(s2[i]);
dfs(1, 0);
FOR(i,1,m) {
scanf("%lld%lld%lld", &x, &y, &z);
y = (y + last_ans) % p;
z = (z + last_ans) % p;
if (y > z) swap(y, z);
ans = query(s1[x], y, z).a;
for (int i = x; fa[i]; i = fa[i]) {
Data t = query(s1[fa[i]], y, z) - query(s2[i], y, z);
ans += t.a + t.b * dist(x, fa[i]);
}
printf("%lld\n", ans);
}
return 0;
}


4012: [HNOI2015]开店

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

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: