题目分析:

  观察题目发现度数不小于三,考虑从边分治入手,用点分治代替。将树划分成重心链接的结构,称为点分树。令当前询问的点为$ u $。那么我们考虑点分树的根到$ u $的一条路径。考虑根结点,排除掉与$ u $有关的点所在的子树,剩下的点到$ u $的路径长度等价于它们到根的路径加上根到$ u $的路径。所以我们要做的是消去$ u $所在子树的影响,然后递归问题。这个做法在点分治意义下是常用做法,前缀和维护即可。由于每个点都在点分路径上的前缀和上出现了一次,而点分树高为$ O(\log n) $,所以空间为$ O(n*\log n) $。时间是$ O(n*\log^2n) $

代码:

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3.  
  4. const int maxn = ;
  5.  
  6. int n,Q,A;
  7.  
  8. int x[maxn];
  9.  
  10. vector <pair<int,int> > g[maxn];
  11. int euler[maxn<<],nE,app[maxn][];
  12. int RMQ[maxn<<][],f[maxn],dep[maxn],climb[maxn];
  13.  
  14. template<typename T>
  15. void in(T &x){
  16. x = ; char ch = getchar();
  17. while(ch > '' || ch < '') ch = getchar();
  18. while(ch >= '' && ch <= '') x = x*+ch-'',ch=getchar();
  19. }
  20.  
  21. void dfs(int now,int last,int dp,int cl){
  22. dep[now] = dp; f[now] = last; climb[now] = cl;
  23. euler[++nE] = now; app[now][] = app[now][] = nE;
  24. for(int i=;i<g[now].size();i++){
  25. int pp = g[now][i].first,len = g[now][i].second;
  26. if(pp == last) continue;
  27. dfs(pp,now,dp+len,cl+);
  28. euler[++nE] = now; app[now][] = nE;
  29. }
  30. }
  31.  
  32. void BuildRMQ(){
  33. for(int i=;i<=nE;i++) RMQ[i][] = euler[i];
  34. for(int k=;(<<k)<=nE;k++){
  35. for(int i=;i<=nE;i++){
  36. if(i+(<<k-) > nE) {RMQ[i][k] = RMQ[i][k-];continue;}
  37. if(climb[RMQ[i][k-]] < climb[RMQ[i+(<<k-)][k-]]){
  38. RMQ[i][k] = RMQ[i][k-];
  39. }else RMQ[i][k] = RMQ[i+(<<k-)][k-];
  40. }
  41. }
  42. }
  43.  
  44. int QueryLCA(int u,int v){
  45. int fst = min(app[u][],app[v][]),sec = max(app[u][],app[v][]);
  46. int len = sec-fst+,k = ;
  47. while((<<k+) <= len) k++;
  48. if(climb[RMQ[fst][k]] < climb[RMQ[sec-(<<k)+][k]]) return RMQ[fst][k];
  49. else return RMQ[sec-(<<k)+][k];
  50. }
  51.  
  52. int dist(int u,int v){ return dep[u]+dep[v]-*dep[QueryLCA(u,v)]; }
  53.  
  54. class Pdivide{
  55. private:
  56. int sz[maxn],arr[maxn],seg[maxn],fa[maxn];
  57. vector <pair<int,int> > v[maxn],v2[maxn];
  58. vector <long long> sum[maxn],sum2[maxn];
  59. stack <int> sta;
  60. void GetSize(int now,int last){
  61. sz[now] = ;seg[now] = ;
  62. for(int i=;i<g[now].size();i++){
  63. int pp = g[now][i].first;
  64. if(arr[pp] || pp == last) continue;
  65. GetSize(pp,now);
  66. sz[now] += sz[pp];
  67. seg[now] = max(seg[now],sz[pp]);
  68. }
  69. sz[now]++;
  70. }
  71. int GetG(int now,int last,int tot){
  72. int res = now; seg[now] = max(seg[now],tot-sz[now]-);
  73. for(int i=;i<g[now].size();i++){
  74. int pp = g[now][i].first;
  75. if(arr[pp] || pp == last) continue;
  76. int p = GetG(pp,now,tot);
  77. if(seg[p] < seg[res]) res = p;
  78. }
  79. return res;
  80. }
  81. void LenQuery(int now,int last,int dst,int root,int oldroot){
  82. v[root].push_back(make_pair(x[now],dst));
  83. if(oldroot != ) v2[root].push_back(make_pair(x[now],dist(now,oldroot)));
  84. for(int i=;i<g[now].size();i++){
  85. int pp = g[now][i].first, len = g[now][i].second;
  86. if(arr[pp] || pp == last) continue;
  87. LenQuery(pp,now,dst+len,root,oldroot);
  88. }
  89. }
  90. void divide(int now,int last,int ht){
  91. GetSize(now,);
  92. int p = GetG(now,,sz[now]);
  93.  
  94. LenQuery(p,,,p,last); sort(v[p].begin(),v[p].end()); sum[p].push_back();
  95. sort(v2[p].begin(),v2[p].end()); sum2[p].push_back();
  96. for(int i=;i<v[p].size();i++) sum[p].push_back(sum[p][i]+1ll*v[p][i].second);
  97. for(int i=;i<v2[p].size();i++) sum2[p].push_back(sum2[p][i]+1ll*v2[p][i].second);
  98.  
  99. fa[p] = last;arr[p] = ht;
  100. for(int i=;i<g[p].size();i++){
  101. int nxt = g[p][i].first;
  102. if(arr[nxt]) continue;
  103. divide(nxt,p,ht+);
  104. }
  105. }
  106.  
  107. public:
  108. void BuildTree(){divide(,,);}
  109. void printans(int now,int l,int r,long long &lastans){
  110. int p = now;
  111. while(p != ) sta.push(p),p = fa[p];
  112. long long ans = ;
  113. while(!sta.empty()){
  114. int tp = sta.top();sta.pop();
  115. int pp = lower_bound(v[tp].begin(),v[tp].end(),make_pair(l,))-v[tp].begin();
  116. if(pp == v[tp].size()||v[tp][pp].first > r) break;
  117. int ed = upper_bound(v[tp].begin(),v[tp].end(),make_pair(r,(int)1E9))-v[tp].begin()-;
  118. int len = ed-pp+;
  119. ans += sum[tp][ed+] - sum[tp][pp] + 1ll*len*dist(tp,now);
  120. if(fa[tp]!=)
  121. ans -= (sum2[tp][ed+] - sum2[tp][pp] + 1ll*len*dist(fa[tp],now));
  122. }
  123. while(!sta.empty())sta.pop();
  124. printf("%lld\n",ans);lastans = ans;
  125. }
  126. }T1;
  127.  
  128. void init(){
  129. dfs(,,,);
  130. BuildRMQ();
  131. T1.BuildTree();
  132. }
  133.  
  134. void work(){
  135. long long lastans = ;
  136. for(int i=;i<=Q;i++){
  137. int a,u,v; in(a),in(u),in(v);
  138. u = (1ll*u+lastans)%A;
  139. v = (1ll*v+lastans)%A;
  140. if(u > v) swap(u,v);
  141. T1.printans(a,u,v,lastans);
  142. }
  143. }
  144.  
  145. int main(){
  146. in(n),in(Q),in(A);
  147. for(int i=;i<=n;i++) in(x[i]);
  148. for(int i=;i<n;i++){
  149. int u,v,w; in(u),in(v),in(w);
  150. g[u].push_back(make_pair(v,w));
  151. g[v].push_back(make_pair(u,w));
  152. }
  153. init();
  154. work();
  155. return ;
  156. }

LOJ2116 [HNOI2015] 开店 【点分治】的更多相关文章

  1. BZOJ 4012 [HNOI2015]开店 (树分治+二分)

    题目大意: 给你一棵树,边有边权,点有点权,有很多次询问,求点权$\in[l,r]$的所有节点到某点$x$的距离之和,强制在线 感觉这个题应该放在动态点分之前做= = 套路方法和动态点分是一样的 每次 ...

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

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

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

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

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

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

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

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

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

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

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

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

  8. BZOJ4012 [HNOI2015]开店 (动态点分治)

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

  9. P3241 [HNOI2015]开店 动态点分治

    \(\color{#0066ff}{ 题目描述 }\) 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱. 这样的想 ...

随机推荐

  1. Item 13: 比起iterator优先使用const_iterator

    本文翻译自modern effective C++,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 博客已经迁移到这里啦 STL中的const_iterator等价于pointers-to ...

  2. 剑指offer--4.重建二叉树

    题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2, ...

  3. python-re模块-54

    import re # findall # search # match ret = re.findall('[a-z]+', 'eva egon yuan') # 返回所有满足匹配条件的结果,放在列 ...

  4. codeforces#580 D. Kefa and Dishes(状压dp)

    题意:有n个菜,每个菜有个兴奋值,并且如果吃饭第i个菜立即吃第j个菜,那么兴奋值加ma[i][j],求吃m个菜的最大兴奋值,(n<=18) 分析:定义dp[status][last],statu ...

  5. JavaScript中防止重复提交

    有这么一种情况: 页面有一个按钮,点击之后会触发Ajax请求,但是用户在点击之后,不知道是否点成功了,于是又点了一下,如果不加处理的话,就会进行两次Ajax请求,并且请求的数据都是一样的,对后端的程序 ...

  6. C#设计模式之4:装饰者模式

    装饰者模式 背景是有一家星巴兹咖啡店,由于客源充足,所以决定重新设计他们的收费系统,以前的收费系统中只定义了一个表示饮料的Beverage的基类,它里面定义了一个Cost的方法用来计算饮料的花费,但是 ...

  7. java线程池实现原理

    (1):线程池存在哪些状态,这些状态之间是如何进行切换的呢? (2):线程池的种类有哪些? (3):创建线程池需要哪些参数,这些参数的具体含义是什么? (4):将任务添加到线程池之后运行流程? (5) ...

  8. Latex常用软件

    Linux texMaker sudo apt-get install texlive-full sudo apt-get install texmaker

  9. 阿里巴巴 Java开发手册1.4.0

    <阿里巴巴Java开发手册1.4.0>下载地址: 下载地址:https://102.alibaba.com/downloadFile.do?file=1528269849853/Java_ ...

  10. 字符串正则替换replace第二个参数是函数

    zepto中 //将字符串转成驼峰式的格式 camelize = function (str) { return str.replace(/-+(.)?/g, function (match, chr ...