[LuoGu]P2664 树上游戏
这题真的好.
看到树上路径, 脑子里就要点分治
这一题对于每个点都要计算一遍, 如果暴算实在不好算, 这样我们就可以考虑算贡献.
直接计算每种颜色的贡献.
因为一条过重心的路径中, 可能两边都会有相同颜色, 那么我们就只考虑当前点到分治中心的链上.
然后把多算的这条链上的东西删除就可以了.
Copy From Here
那么我们就可以这样做了:
1.对树进行第一遍dfs,预处理size和上方性质中的贡献。(开一个color数组即可记录贡献),同时记录贡献总和sum
2.枚举跟的所有子树,先把子树扫一遍清除其在color数组中的所有贡献。接着,对于该子树中的每一个点j:
设X=sigma color[j 到根上(不包括根)的所有颜色] 由于这些颜色已经出现过,我们不能在该子树外计算其贡献)
设num为j到根上(不包括根)的颜色数
设Y为size[root]-size[该子树](即所有其他子树+根的点数)
则ans[j]+=sum-X+num*Y;
3.别忘了计算单独root的ans
ans[root]+=sum-color[根的颜色]+size[root]
4.清空贡献数组以及其他东西
Code
#include<bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for(int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
#define drep(i, a, b) for(int i = (a), i##_end_ = (b); i >= i##_end_; --i)
#define clar(a, b) memset((a), (b), sizeof(a))
#define debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long LL;
typedef long double LD;
int read() {
char ch = getchar();
int x = 0, flag = 1;
for (;!isdigit(ch); ch = getchar()) if (ch == '-') flag *= -1;
for (;isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
return x * flag;
}
void write(int x) {
if (x < 0) putchar('-'), x = -x;
if (x >= 10) write(x / 10);
putchar(x % 10 + 48);
}
const int Maxn = 100009;
struct edge {
int to, nxt;
}g[Maxn << 1];
int n, a[Maxn], head[Maxn], e;
void add(int u, int v) {
g[++e] = (edge){v, head[u]}, head[u] = e;
}
void init() {
clar(head, -1);
n = read();
rep (i, 1, n) a[i] = read();
rep (i, 1, n - 1) {
int u = read(), v = read();
add(u, v), add(v, u);
}
}
LL ans[Maxn], vis[Maxn], Tmp, heart;
int size[Maxn];
void dfs(int u, int pa) {
size[u] = 1;
for (int i = head[u]; ~i; i = g[i].nxt) {
int v = g[i].to;
if (v != pa && !vis[v]) {
dfs(v, u);
size[u] += size[v];
}
}
}
void centroid(int u, int pa, int field) {
int bbs = field - size[u];
for (int i = head[u]; ~i; i = g[i].nxt) {
int v = g[i].to;
if (!vis[v] && v != pa) {
centroid(v, u, field);
bbs = max(bbs, size[v]);
}
}
if (bbs < Tmp) Tmp = bbs, heart = u;
}
LL color[Maxn], Sum, cnt[Maxn], size1[Maxn];
void dfs_init(int u, int pa) {
size1[u] = 1; ++cnt[a[u]];
for (int i = head[u]; ~i; i = g[i].nxt) {
int v = g[i].to;
if (v != pa && !vis[v]) {
dfs_init(v, u);
size1[u] += size1[v];
}
}
if (cnt[a[u]] == 1) {
color[a[u]] += size1[u];
Sum += size1[u];
}
--cnt[a[u]];
}
void change(int u, int pa, int delta) {
++cnt[a[u]];
for (int i = head[u]; ~i; i = g[i].nxt) {
int v = g[i].to;
if (v != pa && !vis[v]) change(v, u, delta);
}
if (cnt[a[u]] == 1) {
color[a[u]] += size1[u] * 1ll * delta;
Sum += size1[u] * 1ll * delta;
}
--cnt[a[u]];
}
void count(int u, int pa, int X, int Y, int num) {
++cnt[a[u]];
if (cnt[a[u]] == 1) {
X += color[a[u]];
++Y;
}
ans[u] += Sum - X + num * Y;
for (int i = head[u]; ~i; i = g[i].nxt) {
int v = g[i].to;
if (!vis[v] && v != pa) count(v, u, X, Y, num);
}
--cnt[a[u]];
}
void dfs_clear(int u, int pa) {
color[a[u]] = 0, cnt[a[u]] = 0, size1[u] = 0;
for (int i = head[u]; ~i; i = g[i].nxt) {
int v = g[i].to;
if (v != pa && !vis[v]) dfs_clear(v, u);
}
}
void calc(int u) {
dfs_init(u, 0);
ans[u] += Sum - color[a[u]] + size1[u];
for (int i = head[u]; ~i; i = g[i].nxt) {
int v = g[i].to;
if (!vis[v]) {
++cnt[a[u]];
Sum -= size1[v]; color[a[u]] -= size1[v];
change(v, u, -1);
--cnt[a[u]];
count(v, u, 0, 0, size1[u] - size1[v]);
++cnt[a[u]];
Sum += size1[v]; color[a[u]] += size1[v];
change(v, u, 1);
--cnt[a[u]];
}
}
dfs_clear(u, 0), Sum = 0;
}
void divConquer(int u) {
dfs(u, 0), Tmp = INT_MAX;
centroid(u, 0, size[u]);
calc(heart); vis[heart] = 1;
for (int i = head[heart]; ~i; i = g[i].nxt) {
int v = g[i].to;
if (!vis[v]) divConquer(v);
}
}
void solve() {
divConquer(1);
rep (i, 1, n) printf("%lld\n", ans[i]);
}
int main() {
freopen("LG2664.in", "r", stdin);
freopen("LG2664.out", "w", stdout);
init();
solve();
#ifdef Qrsikno
debug("\nRunning time: %.3lf(s)\n", clock() * 1.0 / CLOCKS_PER_SEC);
#endif
return 0;
}
[LuoGu]P2664 树上游戏的更多相关文章
- Luogu P2664 树上游戏 dfs+树上统计
题目: P2664 树上游戏 分析: 本来是练习点分治的时候看到了这道题.无意中发现题解中有一种方法可以O(N)解决这道题,就去膜拜了一下. 这个方法是,假如对于某一种颜色,将所有这种颜色的点全部删去 ...
- luogu P2664 树上游戏(点分治)
点分治真是一个好东西.可惜我不会 这种要求所有路经的题很可能是点分治. 然后我就不会了.. 既然要用点分治,就想,点分治有哪些优点?它可以\(O(nlogn)\)遍历分治树的所有子树. 那么现在的问题 ...
- P2664 树上游戏
P2664 树上游戏 https://www.luogu.org/problemnew/show/P2664 分析: 点分治. 首先关于答案的统计转化成计算每个颜色的贡献. 1.计算从根出发的路径的答 ...
- 洛谷 P2664 树上游戏 解题报告
P2664 树上游戏 题目描述 \(\text{lrb}\)有一棵树,树的每个节点有个颜色.给一个长度为\(n\)的颜色序列,定义\(s(i,j)\) 为 \(i\) 到 \(j\) 的颜色数量.以及 ...
- ●洛谷P2664 树上游戏
题链: https://www.luogu.org/problemnew/show/P2664题解: 扫描线,线段树维护区间覆盖 https://www.luogu.org/blog/ZJ75211/ ...
- 洛谷P2664 树上游戏
https://www.luogu.org/problemnew/show/P2664 #include<cstdio> #include<algorithm> #includ ...
- 洛谷P2664 树上游戏(点分治)
传送门 题解 因为一个sb错误调了一个晚上……鬼晓得我为什么$solve(rt)$会写成$solve(v)$啊!!!一个$O(logn)$被我硬生生写成$O(n)$了竟然还能过$5$个点……话说还一直 ...
- 洛谷P2664 树上游戏(点分治)
题意 题目链接 Sol 神仙题..Orz yyb 考虑点分治,那么每次我们只需要统计以当前点为\(LCA\)的点对之间的贡献以及\(LCA\)到所有点的贡献. 一个很神仙的思路是,对于任意两个点对的路 ...
- luogu P2644 树上游戏
一道点分难题 首先很自然的想法就是每种颜色的贡献可以分开计算,然后如果你会虚树就可以直接做了 点分也差不多,考虑每个分治重心的子树对它的贡献以及它对它子树的贡献 首先,处理一个\(cnt\)数组,\( ...
随机推荐
- RecyclerView(替代ListView)使用方法介绍
在build.gradle文件加入以下代码 compile 'com.android.support:cardview-v7:21.0.3' compile 'com.android.support: ...
- Spring Boot 动态数据源(多数据源自己主动切换)
本文实现案例场景: 某系统除了须要从自己的主要数据库上读取和管理数据外.另一部分业务涉及到其它多个数据库,要求能够在不论什么方法上能够灵活指定详细要操作的数据库. 为了在开发中以最简单的方法使用,本文 ...
- configuration默认设置
所以 上面的configuration的set可以省略,但是也可以自己改变设置,如下所示:
- 20170221 SE03 打包请求
请求处理:SE03 只会有其中两三个功能,还需要学习. 请求打包,是传输请求时候常用的一种方法. 步骤如下: 注意点:1.打包请求一定仔细检查,不要遗漏 如果请求不多,分开传是更好 ...
- VS1053 datasheet 解读笔记
pdf 10 pdf 11 ` 左右声道 负载,注意这里的负载指LEFT 到GBUF,RIGHT到GBUF.所以后面会有说明GBUF一定不能连接到GND. pdf 14 pdf 14 从上面的引脚定 ...
- matlab max函数
>> a=[1,6,3;7,5,6] a = 1 6 3 7 5 6 >> [q,p]=max(a,[],2) 返回每行最大值,q是结果.p是索引 q = 6 7 p = 2 ...
- bashdb bashdebug
sudo apt-get install bashdb bashdb --debug 一.列出代码和查询代码类: l 列出当前行以下的10行 - 列出正在执行的代码行的前面10行 . 回到正在执行 ...
- redis02---对于key的操作命令
Redis对于key的操作命令 del key1 key2 ... Keyn 作用: 删除1个或多个键 返回值: 不存在的key忽略掉,返回真正删除的key的数量 rename key newkey ...
- react native与原生的交互
一.交互依赖的重要组件 react native 中如果想要调用ios 中相关的方法,必须依赖一个重要的组件nativemodules import { NativeModules } from ' ...
- object_funs.py
#__init__ 构造方法,双下划线 #__del__ 析构方法,在对象就要被垃圾回收前调用.但发生调用 #的具体时间是不可知的.所以建议尽量避免使用__del__ print('-------ex ...