原题链接

被点分治虐的心态爆炸了

题解

发现直接统计路径上的颜色数量很难,考虑转化一下统计方式。对于某一种颜色\(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;
}

洛谷P2664 树上游戏——点分治的更多相关文章

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

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

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

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

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

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

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

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

  5. ●洛谷P2664 树上游戏

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

  6. 【刷题】洛谷 P2664 树上游戏

    题目描述 lrb有一棵树,树的每个节点有个颜色.给一个长度为n的颜色序列,定义s(i,j) 为i 到j 的颜色数量.以及 \[sum_i=\sum_{j=1}^ns(i,j)\] 现在他想让你求出所有 ...

  7. 洛谷P2664 树上游戏

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

  8. P2664 树上游戏

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

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

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

随机推荐

  1. Qt全局坐标和相对坐标

    QMouseEvent中两类坐标系统,一类是窗口坐标,一类是显示器坐标. QPoint QMouseEvent::pos() 返回相对这个widget(重载了QMouseEvent的widget)的位 ...

  2. PYTHON 100days学习笔记008-3:输入和输出

    目录 Day008-03:Python3 输入和输出 1.输出格式美化 1.1 str.format()用法 1.2 旧式字符串格式化 2.读取键盘输入 3.读和写文件 4.文件对象的方法 4.1 f ...

  3. Web前端基础(一)--HTML简介

    HTML简介 超文本标记语言(英语:HyperText Markup Language,简称:HTML)是一种用于创建网页的标准标记语言. HTML文档的后缀名:.html和.htm,这两种后缀名没有 ...

  4. C++零散知识笔记本

    目录 1.符号 1.1符号输出 1.2运算符 2.基本内置类型 wchar_t 3.内置类型所占字节数 内置类型的简写 4.变量的本质 变量与指针的故事 (1)malloc函数 (2)new关键字 5 ...

  5. 搜索(BFS、DFS、回溯)

    这类题是最简单的了都是一个套路,不像动态规划一类题一个套路,没做过就是不会也极难想出来. 一.BFS 解决的问题:用来初始点解决到指定点的最短路径问题,因为图的每一层上的点到初始点的距离相同.(注意是 ...

  6. C++ Primer练习题day1

    /* 练习1.1略 练习1.2.改写程序,让他返回-1. 练习1.3.编写程序,在标准的输出上打印Hello,World. */ #include<iostream> int main() ...

  7. MySQL的安装 --windows版本

    下载 第一步:打开网址,https://www.mysql.com/ ,点击downloads之后跳转到 https://www.mysql.com/downloads/ 第二步 :跳转至网址 htt ...

  8. VS2017的一些调试方法技巧

    一.基本的操作. 1.启动调试. 可以通过VS的调试(Debug)菜单启动调试.点击调试菜单下的“启动调试”或者按F5键启动.如果你已经在代码中加入了断点,那么执行会自动开始. 注:退出调试快捷键sh ...

  9. docker-registry的定制和性能分析

    docker-index Web UI Meta-data 元数据存储(附注.星级.公共库清单) 访问认证 token管理 存储镜像.以及镜像层的家族谱系 没有用户账户数据 不知道用户的账户和安全性 ...

  10. Java多线程(十一):线程组

    线程组 线程组可以批量管理线程和线程组对象. 一级关联 例子如下,建立一级关联. public class MyThread43 implements Runnable{ public void ru ...