采蘑菇

Time Limit: 20 Sec  Memory Limit: 256 MB

Description

  

Input

  

Output

  

Sample Input

  5
  1 2 3 2 3
  1 2
  1 3
  2 4
  2 5

Sample Output

  10
  9
  12
  9
  11

HINT

  

Main idea

  询问从以每个点为起始点时,各条路径上的颜色种类的和。

Solution

  我们看到题目,立马想到了O(n^2)的做法,然后从这个做法研究一下本质,我们确定了可以以点分治作为框架。

  我们先用点分治来确定一个center(重心)。然后计算跟这个center有关的路径。设现在要统计的是经过center,对x提供贡献的路径。

  我们先记录一个记录Sum[x]表示1~i-1子树中 颜色x 第一次出现的位置的那个点 的子树和,然后我们就利用这个Sum来解题。

  我们显然可以分两种情况来讨论:

  (1)统计center->x出现颜色的贡献
    显然,这时候,对于center->x这一段,直接像O(n^2)做法那样记录一个color表示到目前为止出现的颜色个数,然后加一下即可。再记录一个record表示当前可有的贡献和,一旦出现过一个颜色,那么这个颜色在1~i-1子树上出现第一次以下的点,对于x就不再提供贡献了,record减去Sum[这个颜色],然后这样深搜往下计算即可。

  (2)统计center->x没出现过的颜色的贡献
    显然,对于center->x上没出现过的颜色,直接往下深搜,一开始为record为(All - Sum[center]),一旦出现了一个颜色,record则减去这个Sum。同样表示不再提供贡献即可。

  我们这样做就可以求出每个子树前缀对于其的贡献了,倒着再做一边即可求出全部的贡献。统计x的时候,顺便统计一下center。可以满足效率,成功AC这道题。

Code

  1. #include<iostream>
  2. #include<algorithm>
  3. #include<cstdio>
  4. #include<cstring>
  5. #include<cstdlib>
  6. #include<cmath>
  7. using namespace std;
  8.  
  9. const int ONE = ;
  10. const int INF = ;
  11. const int MOD = 1e9+;
  12.  
  13. int n,x,y;
  14. int Val[ONE];
  15. int next[ONE],first[ONE],go[ONE],tot;
  16. int vis[ONE];
  17. int Ans[ONE],Sum[ONE];
  18. int All;
  19.  
  20. int get()
  21. {
  22. int res,Q=; char c;
  23. while( (c=getchar())< || c>)
  24. if(c=='-')Q=-;
  25. if(Q) res=c-;
  26. while((c=getchar())>= && c<=)
  27. res=res*+c-;
  28. return res*Q;
  29. }
  30.  
  31. void Add(int u,int v)
  32. {
  33. next[++tot]=first[u]; first[u]=tot; go[tot]=v;
  34. next[++tot]=first[v]; first[v]=tot; go[tot]=u;
  35. }
  36.  
  37. namespace Point
  38. {
  39. int center;
  40. int Stack[ONE],top;
  41. int total,Max,center_vis[ONE];
  42. int num,V[ONE];
  43.  
  44. struct power
  45. {
  46. int size,maxx;
  47. }S[ONE];
  48.  
  49. void Getsize(int u,int father)
  50. {
  51. S[u].size=;
  52. S[u].maxx=;
  53. for(int e=first[u];e;e=next[e])
  54. {
  55. int v=go[e];
  56. if(v==father || center_vis[v]) continue;
  57. Getsize(v,u);
  58. S[u].size += S[v].size;
  59. S[u].maxx = max(S[u].maxx,S[v].size);
  60. }
  61. }
  62.  
  63. void Getcenter(int u,int father,int total)
  64. {
  65. S[u].maxx = max(S[u].maxx,total-S[u].size);
  66. if(S[u].maxx < Max)
  67. {
  68. Max = S[u].maxx;
  69. center = u;
  70. }
  71.  
  72. for(int e=first[u];e;e=next[e])
  73. {
  74. int v=go[e];
  75. if(v==father || center_vis[v]) continue;
  76. Getcenter(v,u,total);
  77. }
  78. }
  79.  
  80. void Ad_sum(int u,int father)
  81. {
  82. if(!vis[Val[u]])
  83. {
  84. Stack[++top] = Val[u];
  85. All += S[u].size; Sum[Val[u]] += S[u].size;
  86. }
  87. vis[Val[u]]++;
  88. for(int e=first[u];e;e=next[e])
  89. {
  90. int v=go[e];
  91. if(v==father || center_vis[v]) continue;
  92. Ad_sum(v,u);
  93. }
  94. vis[Val[u]]--;
  95. }
  96.  
  97. void Calc_in(int u,int father,int center,int Size,int f_time,int record)
  98. {
  99. if(!vis[Val[u]]) f_time++, record += Size, record -= Sum[Val[u]];
  100. Ans[u] += record; Ans[center]+=f_time;
  101. Ans[u] += f_time; vis[Val[u]] ++;
  102. for(int e=first[u];e;e=next[e])
  103. {
  104. int v=go[e];
  105. if(v==father || center_vis[v]) continue;
  106. Calc_in(v,u,center,Size,f_time,record);
  107. }
  108. vis[Val[u]] --;
  109. }
  110.  
  111. void Calc_not(int u,int father,int record)
  112. {
  113. if(!vis[Val[u]]) record -= Sum[ Val[u] ];
  114. Ans[u] += record; vis[Val[u]] ++;
  115. for(int e=first[u];e;e=next[e])
  116. {
  117. int v=go[e];
  118. if(v==father || center_vis[v]) continue;
  119. Calc_not(v,u,record);
  120. }
  121. vis[Val[u]] --;
  122. }
  123.  
  124. void Dfs(int u)
  125. {
  126. Max = n;
  127. Getsize(u,);
  128. Getcenter(u,,S[u].size);
  129. Getsize(center,);
  130. center_vis[center] = ;
  131.  
  132. int num=; for(int e=first[center];e;e=next[e]) if(!center_vis[go[e]]) V[++num]=go[e];
  133.  
  134. for(int i=;i<=num;i++)
  135. {
  136. int v=V[i];
  137. int Size = S[center].size - S[v].size - ;
  138. vis[Val[center]] = ;
  139. Calc_in(v,center,center, Size,,All - Sum[Val[center]] + Size);
  140. vis[Val[center]] = ;
  141. Ad_sum(v,center);
  142. }
  143. while(top) Sum[Stack[top--]]=; All=;
  144.  
  145. for(int i=num;i>=;i--)
  146. {
  147. int v=V[i];
  148. vis[Val[center]] = ;
  149. Calc_not(v,center, All-Sum[Val[center]]);
  150. vis[Val[center]] = ;
  151. Ad_sum(v,center);
  152. }
  153.  
  154. while(top) Sum[Stack[top--]]=; All=;
  155. for(int e=first[center];e;e=next[e])
  156. {
  157. int v=go[e];
  158. if(center_vis[v]) continue;
  159. Dfs(v);
  160. }
  161. }
  162.  
  163. }
  164.  
  165. int main()
  166. {
  167. n=get();
  168. for(int i=;i<=n;i++) Val[i]=get();
  169.  
  170. for(int i=;i< n;i++)
  171. {
  172. x=get(); y=get();
  173. Add(x,y);
  174. }
  175.  
  176. Point:: Dfs();
  177. for(int i=;i<=n;i++)
  178. printf("%d\n",Ans[i]+);
  179. }

【Foreign】采蘑菇 [点分治]的更多相关文章

  1. [Luogu 2656] 采蘑菇

    Description 小胖和ZYR要去ESQMS森林采蘑菇. ESQMS森林间有N个小树丛,M条小径,每条小径都是单向的,连接两个小树丛,上面都有一定数量的蘑菇.小胖和ZYR经过某条小径一次,可以采 ...

  2. 洛谷——P2656 采蘑菇

    P2656 采蘑菇 题目描述 小胖和ZYR要去ESQMS森林采蘑菇. ESQMS森林间有N个小树丛,M条小径,每条小径都是单向的,连接两个小树丛,上面都有一定数量的蘑菇.小胖和ZYR经过某条小径一次, ...

  3. 洛谷—— P2656 采蘑菇

    https://www.luogu.org/problem/show?pid=2656 题目描述 小胖和ZYR要去ESQMS森林采蘑菇. ESQMS森林间有N个小树丛,M条小径,每条小径都是单向的,连 ...

  4. 【细节题 离线 树状数组】luoguP4919 Marisa采蘑菇

    歧义差评:但是和题意理解一样了之后细节依然处理了很久,说明还是水平不够…… 题目描述 Marisa来到了森林之中,看到了一排nn个五颜六色的蘑菇,编号从1-n1−n,这些蘑菇的颜色分别为col[1], ...

  5. F 采蘑菇的克拉莉丝

    这是一道树链剖分的题目: 很容易想到,我们在树剖后,对于操作1,直接单点修改: 对于答案查询,我们直接的时候,我们假设查询的点是3,那么我们在查询的时候可分为两部分: 第一部分:查找出除3这颗子树以外 ...

  6. Luogu P2656 采蘑菇

    尽管是缩点的习题,思路也是在看了题解后才明白的. 首先,每个强连通分量内的点都是一定互通的,也就是可以完全把这里面的边都跑满,摘掉所有能摘的蘑菇.那么,考虑给每一个强连通分量化为的新点一个点权,代表摘 ...

  7. [Luogu1119]采蘑菇

    题目大意: 给你一个无向图,点i在时间t[i]之前是不存在的,有q组询问,问你时间为t时从x到y的最短路. 点的编号按出现的时间顺序给出,询问也按照时间顺序给出. 思路: Floyd. Floyd的本 ...

  8. [Luogu2656]采蘑菇

    题目大意: 给你一个有向图,每条边有一个边权w以及恢复系数k, 你从s点出发乱走,经过某条边时会获得相应的收益w,而当第二次经过这条边时相应的收益为w*k下取整. 问你最大能获得的收益为多少? 思路: ...

  9. Wannafly Camp 2020 Day 2F 采蘑菇的克拉莉丝 - 树链剖分

    如果暴力维护,每次询问时需要对所有孩子做计算 考虑通过树剖来平衡修改与询问的时间,询问时计算重链和父树,轻链的贡献预先维护好,修改时则需要修改可能影响的轻链贡献,因为某个点到根的路径上轻重交替只有 \ ...

随机推荐

  1. rails 中 preload、includes、Eager load、Joins 的区别

    Rails 提供了四种不同加载关联数据的方法.下面就来介绍一下. 一.Preload Preload 是以附加一条查询语句来加载关联数据的 User.preload(:posts).to_a # =& ...

  2. OpenCV入门:(二:加载,显示,修改以及保存图片)

    目标: 1.从图片文件打开图片(imread) 2.显示图片(namedWindow和imshow) 3.转换当前图片为灰色图片(cvtColor) 4.保存图片(imwrite) 代码: #incl ...

  3. 第四篇 Python循环

    While 循环 For 循环

  4. Ruby中数组的&操作

    最近在忙一个项目,好久没有写日志了,项目终于接近尾声,可以适当放松一下,所以记一下在这个项目中发现的有趣事情: 数组的 与 操作 一直以为两个数组A和B相与,谁前谁后都一样,不过这次在项目中突然想试一 ...

  5. Visual Studio Code 配置Go 开发环境最简单的方法!!!

    由于大家都知道的原因,在国内如果想访问go等各种资源,都会遇到某种不可预知的神奇问题.导致在VS Code中安装 go 各种插件都会失败. 于是乎,网上就出现了各种各样的解决方案:什么手动git cl ...

  6. GraphSAGE 代码解析(四) - models.py

    原创文章-转载请注明出处哦.其他部分内容参见以下链接- GraphSAGE 代码解析(一) - unsupervised_train.py GraphSAGE 代码解析(二) - layers.py ...

  7. SQLAlchemy 学习笔记(二):ORM

    照例先看层次图 一.声明映射关系 使用 ORM 时,我们首先需要定义要操作的表(通过 Table),然后再定义该表对应的 Python class,并声明两者之间的映射关系(通过 Mapper). 方 ...

  8. POJ 2161 Chandelier(动态规划)

    Description Lamps-O-Matic company assembles very large chandeliers. A chandelier consists of multipl ...

  9. 使用SetOperations(无序)操作redis

    方法 c参数 s说明 Long add(K key, V... values); K key:集合key V... values:key对应的值 向集合中添加一个或多一个元素 Long remove( ...

  10. 软工实践Beta冲刺(1/7)

    队名:起床一起肝活队 组长博客:博客链接 作业博客:班级博客本次作业的链接 组员情况 组员1(队长):白晨曦 过去两天完成了哪些任务 描述: 1.界面的修改与完善 展示GitHub当日代码/文档签入记 ...