原题链接

被点分治虐的心态爆炸了

题解

发现直接统计路径上的颜色数量很难,考虑转化一下统计方式。对于某一种颜色\(c\),它对一个点的贡献为从这个点出发且包含这种颜色的路径条数。

于是我们先点分一下,然后分别统计经过分治中心的路径对根和对其他点的贡献就行了。

推荐一篇比较详细的题解

代码:

#include <bits/stdc++.h>

using namespace std;

#define N 100000
#define pb push_back
#define ll long long int n, c[N + 5];
vector<int> G[N + 5];
int root, S, sz[N + 5], vis[N + 5], maxsz[N + 5], col[N + 5], w[N + 5];
ll cnt[N + 5], ans[N + 5], sum1, sum2; void getRoot(int u, int pa) {
sz[u] = 1; maxsz[u] = 0;
for (auto v : G[u]) {
if (v == pa || vis[v]) continue;
getRoot(v, u);
sz[u] += sz[v];
maxsz[u] = max(maxsz[u], sz[v]);
}
maxsz[u] = max(maxsz[u], S - sz[u]);
if (!root || maxsz[u] < maxsz[root]) root = u;
} void dfs0(int u, int pa) {
sz[u] = 1;
for (auto v : G[u]) {
if (v == pa || vis[v]) continue;
dfs0(v, u);
sz[u] += sz[v];
}
} void dfs1(int u, int pa) { // 计算w数组
col[c[u]]++;
w[u] = 0;
if (col[c[u]] == 1) w[u] = sz[u];
sum1 += w[u], cnt[c[u]] += w[u];
for (auto v : G[u]) {
if (v == pa || vis[v]) continue;
dfs1(v, u);
}
col[c[u]]--;
} void dfs2(int u, int pa, int k) {
cnt[c[u]] += k * w[u];
sum1 += k * w[u];
for (auto v : G[u]) {
if (v == pa || vis[v]) continue;
dfs2(v, u, k);
}
} void dfs3(int u, int pa) {
col[c[u]]++;
if (col[c[u]] == 1) sum2 += S - cnt[c[u]];
ans[u] += sum1 + sum2;
for (auto v : G[u]) {
if (v == pa || vis[v]) continue;
dfs3(v, u);
}
col[c[u]]--;
if (col[c[u]] == 0) sum2 -= S - cnt[c[u]];
} void clear(int u, int pa) {
cnt[c[u]] = 0;
for (auto v : G[u]) {
if (v == pa || vis[v]) continue;
clear(v, u);
}
} void calc(int u) {
dfs0(u, 0);
S = sz[u], sum1 = 0;
for (auto v : G[u]) {
if (vis[v]) continue;
dfs1(v, u);
}
ans[u] += S + sum1 - cnt[c[u]];
for (auto v : G[u]) {
if (vis[v]) continue;
dfs2(v, u, -1);
S -= sz[v];
col[c[u]]++;
sum2 = S - cnt[c[u]];
dfs3(v, u);
col[c[u]]--;
S += sz[v];
dfs2(v, u, +1);
}
clear(u, 0);
} void solve(int u) {
vis[u] = 1;
calc(u);
for (auto v : G[u]) {
if (vis[v]) continue;
root = 0, S = sz[v], getRoot(v, u);
solve(root);
}
} int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
scanf("%d", &c[i]);
for (int i = 1, x, y; i < n; ++i) {
scanf("%d%d", &x, &y);
G[x].pb(y), G[y].pb(x);
}
root = 0, S = n, getRoot(1, 0);
solve(root);
for (int i = 1; i <= n; ++i) printf("%lld\n", ans[i]);
return 0;
}

最新文章

  1. 找出只含有2,3,5因子构成的数的第N个
  2. linux eclipse
  3. MySQL语法语句大全
  4. ORACLE 11G R2 修改&quot;用户名&quot;
  5. HW4.35
  6. myeclipse启动项目时报:An internal error occurred during: &quot;Launching TestSpring on Tomcat 7.x&quot;. java.lang.NullPointerException 解决方法
  7. iOS 开发 Message Digest Algorithm 5(MD5加密)
  8. cobbler自动安装系统
  9. [SCOI2012]滑雪与时间胶囊
  10. Vue 进阶之路(四)
  11. Redis操作list
  12. poj2456 Aggressive cows(二分查找)
  13. github 添加wiki
  14. DevExpress 使用条形码二维码控件打印
  15. ext3日志模式
  16. 【flask】 学习flask macro 模板
  17. springsecurity basic 认证
  18. 原生Ajax使用
  19. ORACLE 12C RMAN 功能增强
  20. &lt;c:set var=&quot;ctx&quot; value=&quot;${pageContext.request.contextPath}&quot; /&gt;的学习

热门文章

  1. Odoo13 新变化:会计
  2. 日常工作问题解决:centos/linux系统如何检测端口是否打开
  3. 日常工作问题解决:记一次centos7上的lvm表错误解决过程
  4. 《你必须知道的495个C语言问题》读书笔记之第3章:表达式
  5. 解决redis运行期间key值过期但是内存memory依然占用过高
  6. TypeScript的类型
  7. 【模板】C++高精度加法
  8. COGS 2633. [HZOI 2016] 数列操作e
  9. git 使用中报错:LF will be replaced by CRLF in app.json
  10. VS2017生成一个简单的DLL文件 和 LIB文件——C语言