[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\)数组,\( ...
随机推荐
- Android Studio 使用正式签名进行调试
在Android Studio中,能够使用Gradle进行打包时自己主动签名. 事实上Android Studio默认会给调试应用加上Debug签名,但有时候调一些第三方SDK时.须要正式签名才干调起 ...
- 文件宝局域网传输/播放功能Windows10系统经验贴(感谢文件宝用户@卡卡罗特 和@24K 純情)
本文由文件宝用户@卡卡罗特 和@24K 純情 两位用户提供,感谢二位. 先分享一个软件开发者的博客,http://www.cnblogs.com/flychen/也许里面的说明就能解决你的问题. 以下 ...
- A nonrecursive list compacting algorithm
A nonrecursive list compacting algorithm Each Erlang process has its own stack and heap which are al ...
- #1241 : Best Route in a Grid
时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 给定一个N行N列的非负整数方阵,从左上角(1,1)出发,只能向下或向右走,且不能到达值为0的方格,求出一条到达右下角的最佳 ...
- read appSettings in configuration file by XElement with xmlns
https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/how-to-write-queries- ...
- Java语言基础二
1.常量的概述和使用 A:什么是常量 B:Java中常量的分类 常量分类为六种:a.”字符串” b.’字符’ c.整数 d.小数 e.boolern(布尔类型) 返回值为 FALSE和TRUE ...
- java.lang.IllegalArgumentException: No converter found for return value of type: class com.st.bean.User
原因:springmvc默认是没有对象转换成json的转换器的,要添加jackson依赖 在pom.xml中添加 <dependency> <groupId>com.faste ...
- codeforces 450C. Jzzhu and Chocolate 解题报告(449A)
题目链接:http://codeforces.com/contest/450/problem/C 题目意思:给出一个 n * m 大小的chocolate bar,你需要在这个bar上切 k 刀,使得 ...
- Python小练习_将数据库中表数据存到redis里
# ##练习:将xxx数据库中my_user表中数据存到redis里面# 分析: pymysql.json.redis# 1.连接数据库,查到数据库里面所有的数据,游标类型要用pymysql.curs ...
- BZOJ_3063_[Usaco2013]Route Designing_DP
BZOJ_3063_[Usaco2013]Route Designing_DP Description After escaping from the farm, Bessie has decided ...