Portal

这题真的好.

看到树上路径, 脑子里就要点分治

这一题对于每个点都要计算一遍, 如果暴算实在不好算, 这样我们就可以考虑算贡献.

直接计算每种颜色的贡献.

因为一条过重心的路径中, 可能两边都会有相同颜色, 那么我们就只考虑当前点到分治中心的链上.

然后把多算的这条链上的东西删除就可以了.

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 树上游戏的更多相关文章

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

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

  2. luogu P2664 树上游戏(点分治)

    点分治真是一个好东西.可惜我不会 这种要求所有路经的题很可能是点分治. 然后我就不会了.. 既然要用点分治,就想,点分治有哪些优点?它可以\(O(nlogn)\)遍历分治树的所有子树. 那么现在的问题 ...

  3. P2664 树上游戏

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

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

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

  5. ●洛谷P2664 树上游戏

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

  6. 洛谷P2664 树上游戏

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

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

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

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

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

  9. luogu P2644 树上游戏

    一道点分难题 首先很自然的想法就是每种颜色的贡献可以分开计算,然后如果你会虚树就可以直接做了 点分也差不多,考虑每个分治重心的子树对它的贡献以及它对它子树的贡献 首先,处理一个\(cnt\)数组,\( ...

随机推荐

  1. windows下使用F2PY编译fortran文件的问题

    在windo系统下F2PY不支持gcc+gfortran的组合,解决的办法: 1.安装mingw和msys,在msys环境下使用F2PY调用gcc+gfortran进行编译 2.放弃F2PY,直接gf ...

  2. Design Pattern 设计模式1 - Strategy 1

    实现 : Defferent Heros attack Defferently. - 不同的英雄使用不用的招数 Strategy设计的思路: 基类A.更加小的基类B,新的继承类C: 1 从基类A中抽出 ...

  3. android5.0(Lollipop) BLE Peripheral牛刀小试

    转载请表明作者:http://blog.csdn.net/lansefeiyang08/article/details/46468743 知道Android L对蓝牙对了一些改进.包含加入A2dp s ...

  4. 基于第三方微信授权登录的iOS代码分析

    本文转载至 http://www.cocoachina.com/ios/20140922/9715.html 微信已经深入到每一个APP的缝隙,最常用的莫过分享和登录了,接下来就以代码的形式来展开微信 ...

  5. React 编码

    https://github.com/Minwe/style-guide/blob/master/React.js.md https://github.com/planningcenter/react ...

  6. 安装程序工具 (Installutil.exe)22

    网址:https://msdn.microsoft.com/zh-cn/library/50614e95(VS.80).aspx  安装程序工具 (Installutil.exe) .NET Fram ...

  7. 推箱子 hdu1254

    推箱子 1  http://acm.hdu.edu.cn/showproblem.php?pid=1254 推箱子 2  http://acm.hzau.edu.cn/problem.php?id=1 ...

  8. codeforces 672C C. Recycling Bottles(计算几何)

    题目链接: C. Recycling Bottles time limit per test 2 seconds memory limit per test 256 megabytes input s ...

  9. poj-1273 Drainage Ditches(最大流基础题)

    题目链接: Drainage Ditches Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 67475   Accepted ...

  10. 深入理解dispatch_sync

    关于GCD的基础知识,之前写过一篇博客,详见GCD基础知识.虽然之前已经梳理过了,但对很多知识点的理解仍然不够透彻…写这篇博客的原因是在阅读AFNetworking代码时遇到一些奇怪的代码. 如下: ...