原题链接

被点分治虐的心态爆炸了

题解

发现直接统计路径上的颜色数量很难,考虑转化一下统计方式。对于某一种颜色\(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. Vue CLI 3 如何自定义 js 的文件名

    参考链接:https://blog.csdn.net/weixin_33979363/article/details/88742342

  2. spring中的ApplicationListener监听器

    监听器在使用过程中可以监听到某一事件的发生,进而对事件做出相应的处理. 首先自定义一个监听器myListener实现ApplicationListener接口 @Repository public c ...

  3. jdbc配置及使用测试

    源码:https://github.com/xiaostudy/jdbc_test1 这是没有使用连接池的 目录 创建的sql语句create.sql DROP TABLE IF EXISTS t_u ...

  4. 算法详解之Tarjan

    "tarjan陪伴强联通分量 生成树完成后思路才闪光 欧拉跑过的七桥古塘 让你 心驰神往"----<膜你抄> 一.tarjan求强连通分量 什么是强连通分量? 引用来自 ...

  5. [OpenCV] 图像亮度和对比度调整

    对比度调整的原理参考这篇博客 以下是代码实现: #include <iostream> #include "opencv2/core.hpp" #include &qu ...

  6. 原生js实现图片的3d效果

    <!doctype html><html lang="en"><head><meta charset="UTF-8"& ...

  7. kafka 名词解释及原理解析过程(三)

    为什么要了解这些名词的解释呢?因为在学一个新的知识或者领域的时候,我们需要知道它所定义的概念和名词意思,因为只有这样我们才能理解和掌握这个新的知识点,才能更加系统的掌握这个技术. 一.名词解释 1.b ...

  8. java源码--Vector和Stack

    一.Vector简介 1.1.Vector概述 通过API中可以知道: 1)Vector是一个可变化长度的数组 2)Vector增加长度通过的是capacity和capacityIncrement这两 ...

  9. 回炉重铸系列之javaEE基础

    这篇文章主要介绍 servlet filter listener interceptor 之 知识点.博文主要从 概念,生命周期,使命介绍其区别.详情如下:   概念 生命周期 使命 servlet ...

  10. Java手写简单Linkedlist一(包括增加,插入,查找,toString,remove功能)

    @Java300 学习总结 一.自定义节点 LinkList底层为双向链表.特点为查询效率低,但增删效率高,线程不安全. 链表数据储存在节点,且每个节点有指向上个和下个节点的指针. 创建ggLinke ...