题目链接:https://www.luogu.org/problem/P2664

题意:给定一颗带点权的树,结点数n<=1e5,点权<=1e5,用s(i,j)表示从i到j的路径上不同点权数,ans[i]=sum(s(i,j))。求ans数组。

思路:

  继续肝淀粉质,太难了。

  涉及到树上点对,且nlogn满足时,就可以考虑考虑点分治了。所以回到这题,我们需要在O(n)时间内统计出以p为根节点的子树上所有节点对p的贡献,以及对所有经过p的路径的贡献。

  

  我们通过dfs1得到这些贡献值和他们的和sum,显然子树上所有节点对p的贡献就是sum,即ans[p]+=sum。

  

  另外,sum、ans数组和color数组需要用LL,在这wa了两发。

AC代码:

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<cctype>
  4. using namespace std;
  5.  
  6. inline int read(){
  7. int x=,f=;char c=;
  8. while(!isdigit(c)){f|=c=='-';c=getchar();}
  9. while(isdigit(c)) x=(x<<)+(x<<)+(c^),c=getchar();
  10. return f?-x:x;
  11. }
  12.  
  13. typedef long long LL;
  14. const int maxn=1e5+;
  15. const int inf=0x3f3f3f3f;
  16. struct node{
  17. int v,nex;
  18. }edge[maxn<<];
  19.  
  20. int n,c[maxn],ct,head[maxn],Min,root,size,sz[maxn],mson[maxn];
  21. int cnt[maxn],num,t,vis[maxn];
  22. LL ans[maxn],color[maxn],sum;
  23.  
  24. void adde(int u,int v){
  25. edge[++ct].v=v;
  26. edge[ct].nex=head[u];
  27. head[u]=ct;
  28. }
  29.  
  30. void getroot(int u,int fa){
  31. sz[u]=,mson[u]=;
  32. for(int i=head[u];i;i=edge[i].nex){
  33. int v=edge[i].v;
  34. if(v==fa||vis[v]) continue;
  35. getroot(v,u);
  36. sz[u]+=sz[v];
  37. if(sz[v]>mson[u]) mson[u]=sz[v];
  38. }
  39. if(size-sz[u]>mson[u]) mson[u]=size-sz[u];
  40. if(mson[u]<Min) Min=mson[u],root=u;
  41. }
  42.  
  43. void dfs1(int u,int fa){
  44. sz[u]=;
  45. ++cnt[c[u]];
  46. for(int i=head[u];i;i=edge[i].nex){
  47. int v=edge[i].v;
  48. if(v==fa||vis[v]) continue;
  49. dfs1(v,u);
  50. sz[u]+=sz[v];
  51. }
  52. if(cnt[c[u]]==){
  53. sum+=sz[u];
  54. color[c[u]]+=sz[u];
  55. }
  56. --cnt[c[u]];
  57. }
  58.  
  59. void change(int u,int fa,int f){
  60. ++cnt[c[u]];
  61. for(int i=head[u];i;i=edge[i].nex){
  62. int v=edge[i].v;
  63. if(v==fa||vis[v]) continue;
  64. change(v,u,f);
  65. }
  66. if(cnt[c[u]]==){
  67. sum+=sz[u]*f;
  68. color[c[u]]+=sz[u]*f;
  69. }
  70. --cnt[c[u]];
  71. }
  72.  
  73. void dfs2(int u,int fa){
  74. ++cnt[c[u]];
  75. if(cnt[c[u]]==){
  76. sum-=color[c[u]];
  77. ++num;
  78. }
  79. ans[u]+=sum+num*t;
  80. for(int i=head[u];i;i=edge[i].nex){
  81. int v=edge[i].v;
  82. if(vis[v]||v==fa) continue;
  83. dfs2(v,u);
  84. }
  85. if(cnt[c[u]]==){
  86. sum+=color[c[u]];
  87. --num;
  88. }
  89. --cnt[c[u]];
  90. }
  91.  
  92. void clear(int u,int fa){
  93. cnt[c[u]]=color[c[u]]=;
  94. for(int i=head[u];i;i=edge[i].nex){
  95. int v=edge[i].v;
  96. if(vis[v]||v==fa) continue;
  97. clear(v,u);
  98. }
  99. }
  100.  
  101. void solve(int u){
  102. dfs1(u,);
  103. ans[u]+=sum;
  104. for(int i=head[u];i;i=edge[i].nex){
  105. int v=edge[i].v;
  106. if(vis[v]) continue;
  107. ++cnt[c[u]],sum-=sz[v],color[c[u]]-=sz[v];
  108. change(v,u,-);--cnt[c[u]];
  109. t=sz[u]-sz[v];
  110. dfs2(v,u);
  111. ++cnt[c[u]],sum+=sz[v],color[c[u]]+=sz[v];
  112. change(v,u,);--cnt[c[u]];
  113. }
  114. sum=,num=;
  115. clear(u,);
  116. }
  117.  
  118. void fenzhi(int u){
  119. vis[u]=;
  120. solve(u);
  121. for(int i=head[u];i;i=edge[i].nex){
  122. int v=edge[i].v;
  123. if(vis[v]) continue;
  124. Min=inf,root=,size=sz[v];
  125. getroot(v,);
  126. fenzhi(root);
  127. }
  128. }
  129.  
  130. int main(){
  131. n=read();
  132. for(int i=;i<=n;++i)
  133. c[i]=read();
  134. for(int i=;i<n;++i){
  135. int u=read(),v=read();
  136. adde(u,v);
  137. adde(v,u);
  138. }
  139. Min=inf,root=,size=n;
  140. getroot(,);
  141. fenzhi(root);
  142. for(int i=;i<=n;++i)
  143. printf("%lld\n",ans[i]);
  144. return ;
  145. }

  

luoguP2664树上游戏(点分治)的更多相关文章

  1. 【点分治】luoguP2664 树上游戏

    应该是一道中等难度的点分?麻烦在一些细节. 题目描述 lrb有一棵树,树的每个节点有个颜色.给一个长度为n的颜色序列,定义s(i,j) 为i 到j 的颜色数量.以及 现在他想让你求出所有的sum[i] ...

  2. 洛谷P2664 树上游戏(点分治)

    题意 题目链接 Sol 神仙题..Orz yyb 考虑点分治,那么每次我们只需要统计以当前点为\(LCA\)的点对之间的贡献以及\(LCA\)到所有点的贡献. 一个很神仙的思路是,对于任意两个点对的路 ...

  3. 洛谷P2664 树上游戏——点分治

    原题链接 被点分治虐的心态爆炸了 题解 发现直接统计路径上的颜色数量很难,考虑转化一下统计方式.对于某一种颜色\(c\),它对一个点的贡献为从这个点出发且包含这种颜色的路径条数. 于是我们先点分一下, ...

  4. luoguP2664 树上游戏

    https://www.luogu.org/problemnew/show/P2664 考虑对于每种颜色包含的点和这些点的子节点建出虚树,发现只要将一个联通块中的东西 Dp + 差分一下就行了 当然要 ...

  5. 【洛谷P2664】 树上游戏 点分治

    code: #include <bits/stdc++.h> #define N 200009 #define ll long long #define setIO(s) freopen( ...

  6. 【Luogu2664】树上游戏(点分治)

    [Luogu2664]树上游戏(点分治) 题面 洛谷 题解 很好的一道点分治题. 首先直接点分治,考虑过每个分治重心的链的贡献. 我们从分治重心开始找每种颜色,强制令一种颜色只在其到分治重心的链上第一 ...

  7. 洛谷 P2664 树上游戏 解题报告

    P2664 树上游戏 题目描述 \(\text{lrb}\)有一棵树,树的每个节点有个颜色.给一个长度为\(n\)的颜色序列,定义\(s(i,j)\) 为 \(i\) 到 \(j\) 的颜色数量.以及 ...

  8. P2664 树上游戏

    P2664 树上游戏 https://www.luogu.org/problemnew/show/P2664 分析: 点分治. 首先关于答案的统计转化成计算每个颜色的贡献. 1.计算从根出发的路径的答 ...

  9. Luogu P2664 树上游戏 dfs+树上统计

    题目: P2664 树上游戏 分析: 本来是练习点分治的时候看到了这道题.无意中发现题解中有一种方法可以O(N)解决这道题,就去膜拜了一下. 这个方法是,假如对于某一种颜色,将所有这种颜色的点全部删去 ...

随机推荐

  1. 04 JQuery的使用

    01 对网站首页优化--定时弹出广告 <!-- 作者:offline 时间:2018-09-09 描述:在使用JQ前要导入jquery-1.11.0.min.js包 注意区分js和jq的对象 - ...

  2. CentOS上部署Kubernetes集群

    1.开始前系统环境准备 # 1.设置基本环境 yum install -y net-tools conntrack-tools wget vim ntpdate libseccomp libtool- ...

  3. Luogu P1110 [ZJOI2007]报表统计 multiset

    沿用了学长的$multiset$ 然后这道题可以看到我的程序中有两行注释,它在我看来和他们下面的代码没区别,但是我们发现,C++会先调用后面的参数,所以$--it$会被先执行 ... ... ... ...

  4. luogu 3698 [CQOI2017]小Q的棋盘 树形dp

    Code: #include <bits/stdc++.h> #define N 107 #define setIO(s) freopen(s".in","r ...

  5. 7.20套娃(tao)

    套娃(tao) input7 39 53 710 65 102 610 104 110 53 53 9output012 sol: 把查询想象成(x1,y1)向(x2,y2)有边当且仅当(x1< ...

  6. CF427D

    CF427D SA的奇技淫巧,其实就是板子. 题意: 给定两个字符串,求最短的满足各只出现一次的连续公共字串 解析: 一般情况下,SA都是用来求最长公共前缀的,好像和这道题所求的最短公共子串没有任何关 ...

  7. Netfilter 之 连接跟踪钩子函数分析

    ipv4_conntrack_defrag ipv4_conntrack_defrag对输入包进行检查,如果是分片包,则调用nf_ct_ipv4_gather_frags函数进行重组: static ...

  8. SpringMVC支持跨域请求

    一.如果项目中使用的SpringMVC4.3.9以下,就需要对该请求配置Filter,设置请求头可支持跨域.使用方法: --spring cloud zuul支持跨域---:https://blog. ...

  9. Reflexil

    https://github.com/sailro/Reflexil/issues/47 Instructions on how to install Reflexil would be much a ...

  10. 关于jenkins

    启动不了时可更改端口 java -jar jenkins.war –httpPort=8090