题目描述

lrb有一棵树,树的每个节点有个颜色。给一个长度为n的颜色序列,定义s(i,j) 为i 到j 的颜色数量。以及

\[sum_i=\sum_{j=1}^ns(i,j)
\]

现在他想让你求出所有的sum[i]

输入输出格式

输入格式:

第一行为一个整数n,表示树节点的数量

第二行为n个整数,分别表示n个节点的颜色c[1],c[2]……c[n]

接下来n-1行,每行为两个整数x,y,表示x和y之间有一条边

输出格式:

输出n行,第i行为sum[i]

输入输出样例

输入样例#1:

5

1 2 3 2 3

1 2

2 3

2 4

1 5

输出样例#1:

10

9

11

9

12

说明

  1. sum[1]=s(1,1)+s(1,2)+s(1,3)+s(1,4)+s(1,5)=1+2+3+2+2=10
  2. sum[2]=s(2,1)+s(2,2)+s(2,3)+s(2,4)+s(2,5)=2+1+2+1+3=9
  3. sum[3]=s(3,1)+s(3,2)+s(3,3)+s(3,4)+s(3,5)=3+2+1+2+3=11
  4. sum[4]=s(4,1)+s(4,2)+s(4,3)+s(4,4)+s(4,5)=2+1+2+1+3=9
  5. sum[5]=s(5,1)+s(5,2)+s(5,3)+s(5,4)+s(5,5)=2+3+3+3+1=12

对于40%的数据,n<=2000

对于100%的数据,1<=n,c[i]<=10^5

题解

用的点分治做

这道题我看题解都看了很久啊

nyg和zlt用虚树做的,于是我就只能默默地一个人看点分的做法

首先看找到分治中心后看怎么算根的答案,因为点对中一个点一定是根,所以就是求每个点到根的路径上有多少个不同的颜色;然后把计算答案的方法变一下,把统计点的贡献变成统计颜色的贡献

那么如果一个点的颜色是在这个点到根的路径上第一次出现,那么这个颜色就可以对答案贡献当前点的size大小贡献(因为点对中另一个点只要是这个点的子树中的点,那么由于会经过当前点,而这个点的颜色又是第一次出现,那么肯定每个点对的贡献都会加1,那么对于这个颜色来说,就会加size贡献)

\(colvl[x]\) 代表颜色 \(x\) 的贡献,\(allval\) 就是统计 \(colvl\) 的和

那么根的答案就直接为 \(allval\)

由于分治算的答案都是必经过根的,所以我们接着会发现开始我们统计的 \(colvl[i]\) 同样使用于除根外的其它点 \(x\) ,但要保证 \(x\) 到根的路径上不能出现 \(i\) 的颜色,并且同一子树中的点不能对其颜色有贡献,这不就是点分不去重的搞法吗

然后就好了

每次找完root后,dfs一遍算 \(colvl\) 和 \(allval\),然后把根的贡献搞出来

然后枚举每一个子树,dfs一遍把当前的子树的贡献去掉,再dfs一遍把去掉贡献的子树的答案算一下,最后dfs一遍把去掉的贡献加回来

点分治就做完了

  1. #include<bits/stdc++.h>
  2. #define ui unsigned int
  3. #define ll long long
  4. #define db double
  5. #define ld long double
  6. #define ull unsigned long long
  7. const int MAXN=100000+10,inf=0x3f3f3f3f;
  8. int n,col[MAXN],e,to[MAXN<<1],nex[MAXN<<1],beg[MAXN],Msonsize[MAXN],size[MAXN],root,colnt[MAXN],finish[MAXN];
  9. ll allval,colvl[MAXN],ans[MAXN];
  10. template<typename T> inline void read(T &x)
  11. {
  12. T data=0,w=1;
  13. char ch=0;
  14. while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
  15. if(ch=='-')w=-1,ch=getchar();
  16. while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
  17. x=data*w;
  18. }
  19. template<typename T> inline void write(T x,char ch='\0')
  20. {
  21. if(x<0)putchar('-'),x=-x;
  22. if(x>9)write(x/10);
  23. putchar(x%10+'0');
  24. if(ch!='\0')putchar(ch);
  25. }
  26. template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
  27. template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
  28. template<typename T> inline T min(T x,T y){return x<y?x:y;}
  29. template<typename T> inline T max(T x,T y){return x>y?x:y;}
  30. inline void insert(int x,int y)
  31. {
  32. to[++e]=y;
  33. nex[e]=beg[x];
  34. beg[x]=e;
  35. }
  36. inline void getroot(int x,int f,int total)
  37. {
  38. Msonsize[x]=0;size[x]=1;
  39. for(register int i=beg[x];i;i=nex[i])
  40. if(to[i]==f||finish[to[i]])continue;
  41. else
  42. {
  43. getroot(to[i],x,total);
  44. size[x]+=size[to[i]];
  45. chkmax(Msonsize[x],size[to[i]]);
  46. }
  47. chkmax(Msonsize[x],total-size[x]);
  48. if(Msonsize[x]<Msonsize[root])root=x;
  49. }
  50. inline void dfs1(int x,int f)
  51. {
  52. colnt[col[x]]++;
  53. size[x]=1;
  54. for(register int i=beg[x];i;i=nex[i])
  55. if(to[i]==f||finish[to[i]])continue;
  56. else dfs1(to[i],x),size[x]+=size[to[i]];
  57. if(colnt[col[x]]==1)
  58. {
  59. allval+=size[x];
  60. colvl[col[x]]+=size[x];
  61. }
  62. colnt[col[x]]--;
  63. }
  64. inline void dfs2(int x,int f,int k)
  65. {
  66. colnt[col[x]]++;
  67. for(register int i=beg[x];i;i=nex[i])
  68. if(to[i]==f||finish[to[i]])continue;
  69. else dfs2(to[i],x,k);
  70. if(colnt[col[x]]==1)
  71. {
  72. allval+=k*size[x];
  73. colvl[col[x]]+=k*size[x];
  74. }
  75. colnt[col[x]]--;
  76. }
  77. inline void dfs3(int x,int f,int other,int colnm)
  78. {
  79. colnt[col[x]]++;
  80. if(colnt[col[x]]==1)allval-=colvl[col[x]],colnm++;
  81. ans[x]+=(ll)allval+(ll)colnm*other;
  82. for(register int i=beg[x];i;i=nex[i])
  83. if(to[i]==f||finish[to[i]])continue;
  84. else dfs3(to[i],x,other,colnm);
  85. if(colnt[col[x]]==1)allval+=colvl[col[x]],colnm--;
  86. colnt[col[x]]--;
  87. }
  88. inline void clear(int x,int f)
  89. {
  90. colnt[col[x]]=colvl[col[x]]=0;
  91. for(register int i=beg[x];i;i=nex[i])
  92. if(to[i]==f||finish[to[i]])continue;
  93. else clear(to[i],x);
  94. }
  95. inline void calc(int x)
  96. {
  97. allval=0;
  98. dfs1(x,0);
  99. ans[x]+=allval;
  100. for(register int i=beg[x];i;i=nex[i])
  101. if(!finish[to[i]])
  102. {
  103. colnt[col[x]]++;
  104. allval-=size[to[i]];
  105. colvl[col[x]]-=size[to[i]];
  106. dfs2(to[i],x,-1);
  107. colnt[col[x]]--;
  108. dfs3(to[i],x,size[x]-size[to[i]],0);
  109. colnt[col[x]]++;
  110. allval+=size[to[i]];
  111. colvl[col[x]]+=size[to[i]];
  112. dfs2(to[i],x,1);
  113. colnt[col[x]]--;
  114. }
  115. clear(x,0);
  116. }
  117. inline void solve(int x)
  118. {
  119. calc(x);
  120. finish[x]=1;
  121. for(register int i=beg[x];i;i=nex[i])
  122. if(!finish[to[i]])
  123. {
  124. root=0;
  125. getroot(to[i],x,size[to[i]]);
  126. solve(root);
  127. }
  128. }
  129. int main()
  130. {
  131. read(n);
  132. for(register int i=1;i<=n;++i)read(col[i]);
  133. for(register int i=1;i<n;++i)
  134. {
  135. int u,v;
  136. read(u);read(v);
  137. insert(u,v);insert(v,u);
  138. }
  139. Msonsize[0]=inf;
  140. getroot(1,0,n);
  141. solve(root);
  142. for(register int i=1;i<=n;++i)write(ans[i],'\n');
  143. return 0;
  144. }

【刷题】洛谷 P2664 树上游戏的更多相关文章

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

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

  2. ●洛谷P2664 树上游戏

    题链: https://www.luogu.org/problemnew/show/P2664题解: 扫描线,线段树维护区间覆盖 https://www.luogu.org/blog/ZJ75211/ ...

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

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

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

    传送门 题解 因为一个sb错误调了一个晚上……鬼晓得我为什么$solve(rt)$会写成$solve(v)$啊!!!一个$O(logn)$被我硬生生写成$O(n)$了竟然还能过$5$个点……话说还一直 ...

  5. 洛谷P2664 树上游戏

    https://www.luogu.org/problemnew/show/P2664 #include<cstdio> #include<algorithm> #includ ...

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

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

  7. 洛谷P2664 树上游戏 【点分治 + 差分】

    题目 lrb有一棵树,树的每个节点有个颜色.给一个长度为n的颜色序列,定义s(i,j) 为i 到j 的颜色数量.以及 现在他想让你求出所有的sum[i] 输入格式 第一行为一个整数n,表示树节点的数量 ...

  8. [洛谷U40581]树上统计treecnt

    [洛谷U40581]树上统计treecnt 题目大意: 给定一棵\(n(n\le10^5)\)个点的树. 定义\(Tree[l,r]\)表示为了使得\(l\sim r\)号点两两连通,最少需要选择的边 ...

  9. P2664 树上游戏

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

随机推荐

  1. JS 判断checkbox 是否选中

    <input type="checkbox" id="IsEnable" /> 在调试的时候,会出现,一直未true的状态,不管是选中还是未选中 解 ...

  2. 探究linux设备驱动模型之——platform虚拟总线(二)

    上回说到,platform_match是驱动和设备之间的媒人婆,那么platform_match是如何匹配驱动和设备的呢?platform总线定义的匹配条件很简单,主要就是查看驱动结构体和设备结构体的 ...

  3. 如何下载YouTube 60fps视频

    YouTube上面不仅支持分辨率为4K和8K的视频,同时也开启了对60fps视频的支持.60帧的视频广泛用于游戏和体育视频中,使视频看起来更加流畅和细腻.对游戏玩家来说,YouTube对60fps支持 ...

  4. itchat个人练习 语音与文本图灵测试例程

    背景介绍 itchat是一个开源的微信个人号接口,使用python调用微信从未如此简单. 使用不到三十行的代码,你就可以完成一个能够处理所有信息的微信机器人. 官方文档参考https://itchat ...

  5. 用原生JS实现一个轮播(包含全部代码和详细思路)

    在我看来要想实现轮播主要是要知道当前位于的页面和即将位于的页面.这个案例是通过改变图片的透明度来实现轮播的效果. 我把涉及的知识点分为两个方面,分别是HTML+css和JS. 第一部分(html+cs ...

  6. flask ssti python2和python3 注入总结和区别

    总结一下flask ssti的注入语句 代码 import uuid from flask import Flask, request, make_response, session,render_t ...

  7. [转]git命令之git remote的用法

    git remote git  remote -v git init git add xxx git commit -m 'xxx' git remote add origin ssh://softw ...

  8. IO多路复用(一)-- Select、Poll、Epoll

    在上一篇博文中提到了五种IO模型,关于这五种IO模型可以参考博文IO模型浅析-阻塞.非阻塞.IO复用.信号驱动.异步IO.同步IO,本篇主要介绍IO多路复用的使用和编程. IO多路复用的概念 多路复用 ...

  9. 十大经典排序算法总结 (Python)

    作业部落:https://www.zybuluo.com/listenviolet/note/1399285 以上链接是自己在作业部落编辑的排序算法总结- Github: https://github ...

  10. 亚马逊与Twitter携手电子商务

    亚马逊(Amazon)与Twitter开展了合作,允许用户以Twitter消息的形式将喜欢的商品发送到购物篮中.这些高科技企业正在想办法把社交媒体和电子商务融为一体. 这一功能旨在将Twitter转变 ...