题面

洛谷

题解

20pts

直接暴力统计即可,复杂度\(O(NQ)\)。

另20pts

我们考虑动态点分治。

怎么在原树上统计答案呢,我们对点\(x\),

预处理出其子节点数目\(s_0\),其子树内每个点到\(x\)的距离和\(s_1\),以及其子树内每个点到\(fa_x\)的距离和\(s_2\)。

则每次我们暴跳父亲,显然\(s_1[x]+\sum s_1[fa]-s_2[p]+(s_0[fa]-s_0[p])*dis(fa,x)\)就是树上与\(x\)的\(lca\)

为\(fa\)的所有点的距离之和,其中\(fa\)为\(p\)的父亲,\(p\)为从\(x\)不断跳父亲直到根,那么只要不断枚举\(fa\),并不断往上跳并维护答案就可以了。

然而上面只是为了方便理解,因为具体的计算不是这样的。我们对于\(x\)点内部的贡献可以直接计算,然后考虑往上跳。在上述的式子中如果一个点\(p\)有\(fa\),那么答案就要减去\(s_0[p]*dis(fa,x)+s_2[p]\),如果一个点不是\(x\)那么答案就要加上\(s_0[p]+dis(p,x)\),然后每一个点都要加上自己的\(sz_1\)​。

按这个规律在跳的时候不断加就好了。

然后在点分树上维护这个东西就好了,正确性显然。

再对于每个年龄维护一个东西,复杂度\(O(20*Q\log n)\)。

100pts

其实上面讲得差不多了。

每个点维护一个\(vector\),对上述信息进行维护,将每个点的按年龄排序,统计距离的前缀和再分二分年龄即可。

时间复杂度\(O(Q\log^2 n)\),空间复杂度\(O(n\log n)\)。

代码

C++11真的爽

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cstring>
  5. #include <cmath>
  6. #include <algorithm>
  7. #include <vector>
  8. using namespace std;
  9. inline int gi() {
  10. register int data = 0, w = 1;
  11. register char ch = 0;
  12. while (!isdigit(ch) && ch != '-') ch = getchar();
  13. if (ch == '-') w = -1, ch = getchar();
  14. while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar();
  15. return w * data;
  16. }
  17. typedef long long ll;
  18. const int INF = 1e9 + 5;
  19. const int MAX_N = 1.5e5 + 5;
  20. struct Graph { int to, cost, next; } e[MAX_N << 1]; int fir[MAX_N], e_cnt;
  21. void clearGraph() { memset(fir, -1, sizeof(fir)); e_cnt = 0; }
  22. void Add_Edge(int u, int v, int w) { e[e_cnt] = {v, w, fir[u]}; fir[u] = e_cnt++; }
  23. struct Node { int age, dis; ll sum; } ;
  24. inline bool operator < (const Node &l, const Node &r) {
  25. if (l.age == r.age) return l.dis == r.dis ? l.sum < r.sum : l.dis < r.dis;
  26. else return l.age < r.age;
  27. }
  28. vector<Node> vec[2][MAX_N];
  29. int pos[MAX_N], cnt, lg[MAX_N << 1], bin[20];
  30. int md[20][MAX_N << 1], dep[MAX_N];
  31. void dfs(int x, int f) {
  32. md[0][pos[x] = ++cnt] = dep[x];
  33. for (int i = fir[x]; ~i; i = e[i].next) {
  34. int v = e[i].to; if (v == f) continue;
  35. dep[v] = dep[x] + e[i].cost;
  36. dfs(v, x);
  37. md[0][++cnt] = dep[x];
  38. }
  39. }
  40. int dis(int u, int v) {
  41. int tmp = dep[u] + dep[v];
  42. u = pos[u], v = pos[v];
  43. if (u > v) swap(u, v);
  44. int k = lg[v - u + 1];
  45. return tmp - (min(md[k][u], md[k][v - bin[k] + 1]) << 1ll);
  46. }
  47. int fa[MAX_N], size[MAX_N], centroid, rmx, sz;
  48. bool used[MAX_N];
  49. void search_centroid(int x, int f) {
  50. int mx = 0; size[x] = 1;
  51. for (int i = fir[x]; ~i; i = e[i].next) {
  52. int v = e[i].to; if (v == f || used[v]) continue;
  53. search_centroid(v, x); size[x] += size[v];
  54. mx = max(mx, size[v]);
  55. }
  56. mx = max(mx, sz - size[x]);
  57. if (mx < rmx) centroid = x, rmx = mx;
  58. }
  59. void Div(int x) {
  60. used[x] = 1;
  61. for (int i = fir[x]; ~i; i = e[i].next) {
  62. int v = e[i].to; if (used[v]) continue;
  63. rmx = sz = size[v];
  64. centroid = v;
  65. search_centroid(v, x);
  66. fa[centroid] = x;
  67. Div(centroid);
  68. }
  69. }
  70. ll query(int x, int a) {
  71. ll ans = 0;
  72. for (int i = x; i; i = fa[i]) {
  73. int t = lower_bound(vec[0][i].begin(), vec[0][i].end(), (Node){a, 0, 0})
  74. - vec[0][i].begin() - 1;
  75. ans += vec[0][i][t].sum + 1ll * t * dis(i, x);
  76. }
  77. for (int i = x; fa[i]; i = fa[i]) {
  78. int t = lower_bound(vec[1][i].begin(), vec[1][i].end(), (Node){a, 0, 0})
  79. - vec[1][i].begin() - 1;
  80. ans -= vec[1][i][t].sum + 1ll * t * dis(fa[i], x);
  81. }
  82. return ans;
  83. }
  84. int N, Q, A, age[MAX_N];
  85. int main () {
  86. #ifndef ONLINE_JUDGE
  87. freopen("cpp.in", "r", stdin);
  88. #endif
  89. clearGraph();
  90. N = gi(), Q = gi(), A = gi();
  91. for (int i = 1; i <= N; i++) age[i] = gi();
  92. for (int i = 1; i < N; i++) {
  93. int u = gi(), v = gi(), w = gi();
  94. Add_Edge(u, v, w), Add_Edge(v, u, w);
  95. }
  96. dfs(1, 0);
  97. bin[0] = 1; for (int i = 1; i < 20; i++) bin[i] = bin[i - 1] << 1;
  98. for (int i = 1; bin[i] <= cnt; i++)
  99. for (int j = 1; j + bin[i] - 1 <= cnt; j++)
  100. md[i][j] = min(md[i - 1][j], md[i - 1][j + bin[i - 1]]);
  101. for (int i = 2; i <= cnt; i++) lg[i] = lg[i >> 1] + 1;
  102. sz = rmx = N;
  103. search_centroid(1, 0);
  104. Div(centroid);
  105. for (int x = 1; x <= N; ++x)
  106. for (int o = x; o; o = fa[o]) {
  107. vec[0][o].push_back({age[x], dis(x, o), 0});
  108. vec[1][o].push_back({age[x], dis(x, fa[o]), 0});
  109. }
  110. for (int x = 1; x <= N; ++x) {
  111. for (int op = 0; op < 2; ++op) {
  112. vec[op][x].push_back({-1, 0, 0});
  113. vec[op][x].push_back({INF, 0, 0});
  114. sort(vec[op][x].begin(), vec[op][x].end());
  115. for (auto ite = vec[op][x].begin() + 1; ite != vec[op][x].end(); ++ite)
  116. ite -> sum = (ite - 1) -> sum + ite -> dis;
  117. }
  118. }
  119. for (ll ans = 0; Q--; ) {
  120. int x = gi(), a = (ans + gi()) % A, b = (ans + gi()) % A;
  121. if (a > b) swap(a, b);
  122. printf("%lld\n", ans = query(x, b + 1) - query(x, a));
  123. }
  124. return 0;
  125. }

【LG3241】[HNOI2015]开店的更多相关文章

  1. [HNOI2015]开店 树链剖分,主席树

    [HNOI2015]开店 LG传送门 蒟蒻表示不会动态淀粉质. 先把点按年龄排序, 设\(dis[i]\)表示\(i\)到根的距离. 把我们要算的东西稍微变下形:\(ans\) \[ = \sum \ ...

  2. 洛谷 P3241 [HNOI2015]开店 解题报告

    P3241 [HNOI2015]开店 题目描述 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱. 这样的想法当然非 ...

  3. [BZOJ4012][HNOI2015]开店(动态点分治,树链剖分)

    4012: [HNOI2015]开店 Time Limit: 70 Sec  Memory Limit: 512 MBSubmit: 2168  Solved: 947[Submit][Status] ...

  4. 【BZOJ4012】[HNOI2015]开店 动态树分治+二分

    [BZOJ4012][HNOI2015]开店 Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点 ...

  5. BZOJ4012 [HNOI2015]开店

    Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现 ...

  6. bzoj 4012: [HNOI2015]开店

    Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现 ...

  7. bzoj 4012: [HNOI2015]开店 主席树

    Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现 ...

  8. BZOJ4012[HNOI2015]开店——树链剖分+可持久化线段树/动态点分治+vector

    题目描述 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现她们面临着一个 ...

  9. BZOJ4012: [HNOI2015]开店【动态点分治】

    Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现 ...

随机推荐

  1. Java并发案例01---多线程之死锁

    多线程之死锁案例一 package example; /** * 模拟死锁 * @author maple * */ public class DeadLock { public int flag = ...

  2. 对deferred(延迟对象)的理解

    deferred对象从jQuery 1.5.0开始引入 什么是defrred对象 开发网站过程中,我们经常遇到某些耗时长的JS操作,其中,既有异步操作(如Ajax读取服务器数据),也有同步的操作(如遍 ...

  3. 4、Android-数据存储方案(SQLite数据库存储)

    4.4.SQLite数据库存储 这是Android内置的数据库 是一款轻量级的关系型数据库 运算速度非常快.占用资源少.通常只需要几百kb的内存就够了 因而特别适合在移动端设备上使用 SQLite不仅 ...

  4. 10-RabbitMQ-整合SpringBoot

    RabbitMQ整个SpringBoot SpringBoot因其配置简单.快速开发,已经成为热门的开发之一 消息中间件的工作过程可以用生产者消费者模型来表示.即,生产者不断的向消息队列发送信息 而消 ...

  5. 枚举enum和enumerate

    #coding=utf-8 from enum import Enum #定义自己的枚举时需要使用class,继承Enum类 class Color(Enum): red=1 green=2 blue ...

  6. 我的QT5学习之路(目录)

    说明:本目录内容为自己学习的心得和记录,参考资料来源于网络,学习过程中多方汲取,如有错误,欢迎指正和批评. Qt开发相关文章目录 一.我的Qt学习之路系列 1.[笔记]我的Qt学习之路(一)——浅谈Q ...

  7. 用JavaScript中lodash编写双色球

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. 身份认证系统(二)多WEB应用的单点登录

    随着互联网的发展,web应用的复杂度也一直在提升,慢慢的单一的web应用已经不能满足复杂的业务需求.例如百度的搜索.新闻.百科.贴吧,其实本质上都是不同的网站.当用户使用这些平台的时候,我们当然不希望 ...

  9. iOS 利用KeyChain+ IDFV + BundleID 来作为UUID,保证传给服务端的UUID唯一

    查了相关资料,发现只有KeyChain + IDFV可以保证UUID唯一,参考以下代码 , UICKeyChainStore + (NSString*)identifierForVender{ UIC ...

  10. Java监听器原理及实例

    一.监听器原理 监听器是基于事件驱动的,用于对操作事件进行监听.处理,是观察者设计模式的应用 监听器三元素: 2.1 事件源:事件发生的源头 2.2 事件:对事件进行抽象.封装 2.3 监听器:用于监 ...