题目

lrb有一棵树,树的每个节点有个颜色。给一个长度为n的颜色序列,定义s(i,j) 为i 到j 的颜色数量。以及

现在他想让你求出所有的sum[i]

输入格式

第一行为一个整数n,表示树节点的数量

第二行为n个整数,分别表示n个节点的颜色c[1],c[2]……c[n]

接下来n-1行,每行为两个整数x,y,表示x和y之间有一条边

输出格式

输出n行,第i行为sum[i]

输入样例

5
1 2 3 2 3
1 2
2 3
2 4
1 5

输出样例

10
9
11
9
12

提示

sum[1]=s(1,1)+s(1,2)+s(1,3)+s(1,4)+s(1,5)=1+2+3+2+2=10
sum[2]=s(2,1)+s(2,2)+s(2,3)+s(2,4)+s(2,5)=2+1+2+1+3=9
sum[3]=s(3,1)+s(3,2)+s(3,3)+s(3,4)+s(3,5)=3+2+1+2+3=11
sum[4]=s(4,1)+s(4,2)+s(4,3)+s(4,4)+s(4,5)=2+1+2+1+3=9
sum[5]=s(5,1)+s(5,2)+s(5,3)+s(5,4)+s(5,5)=2+3+3+3+1=12
对于40%的数据,n<=2000

对于100%的数据,1<=n,c[i]<=10^5

题解

明显点分治即可

对于每棵分治出来的树,考虑过根的所有路径对树内点的影响
首先单独考虑一种颜色的影响,从根节点出发到每棵子树的每个点\(u\),\(u\)节点在该颜色下会产生贡献当且仅当\(u\)到根的路径上有该颜色的节点
所以我们只要找出一个子树中所有颜色为该颜色,且其祖先中没有该颜色【也就是最高的该颜色点】,其子树所有点都会产生贡献,那么所有的对根的贡献就是所有这样点的子树大小之和

考虑对子树内的点,就减去该子树的贡献,就转化为和根类似的了
每当第一次经过一种颜色的点时,其子树内所有点经过该点必定产生该颜色的贡献,此时把该颜色的贡献改为剩余子树的大小即可

还有,根节点的颜色特殊考虑

不知讲清楚没有,仔细想想还是很明显的

不过写起来细节真的多

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long int
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
using namespace std;
const int maxn = 100005,maxm = 200005,INF = 1000000000;
inline int read(){int out = 0,flag = 1; char c = getchar();while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}return out * flag;
}
int h[maxn],ne = 2;
struct EDGE{int to,nxt;}ed[maxm];
inline void build(int u,int v){ed[ne] = (EDGE){v,h[u]}; h[u] = ne++;ed[ne] = (EDGE){u,h[v]}; h[v] = ne++;
}
int n,c[maxn],F[maxn],N,Siz[maxn],rt,vis[maxn],fa[maxn];
int id[maxn],st[maxn],top,Vis[maxn],now,tot,tots;
LL D[maxn],Sum[maxn],sum[maxn],Sumt[maxn],ttt;
void getrt(int u){Siz[u] = 1; F[u] = 0;Redge(u) if (!vis[to = ed[k].to] && to != fa[u]){fa[to] = u; getrt(to);Siz[u] += Siz[to];F[u] = max(F[u],Siz[to]);}F[u] = max(F[u],N - Siz[u]);if (F[u] < F[rt]) rt = u;
}
void dfs1(int u){Siz[u] = 1;if (!id[c[u]]) st[++top] = c[u],id[c[u]] = top;Redge(u) if (!vis[to = ed[k].to] && to != fa[u]){fa[to] = u; dfs1(to);Siz[u] += Siz[to];}
}
void dfs2(int u){int p = id[c[u]],flag = 0;if (p != 1 && Vis[p] != now) Sum[p] += Siz[u],Vis[p] = now,flag = 1;Redge(u) if (!vis[to = ed[k].to] && to != fa[u]) dfs2(to);if (flag) Vis[p] = 0;
}
void dfs3(int u){int p = id[c[u]],flag = 0;if (p != 1 && Vis[p] != now) Sumt[p] += Siz[u],ttt += Siz[u],Vis[p] = now,flag = 1;Redge(u) if (!vis[to = ed[k].to] && to != fa[u]) dfs3(to);if (flag) Vis[p] = 0;
}
void dfs4(int u){int p = id[c[u]],flag = 0;D[u] = D[fa[u]];if (p != 1 && Vis[p] != now){D[u] -= (Sum[p] - Sumt[p]) - (tot - tots);Vis[p] = now; flag = 1;}sum[u] += D[u] + (tot - tots);Redge(u) if (!vis[to = ed[k].to] && to != fa[u]) dfs4(to);if (flag) Vis[p] = 0;
}
void dfs5(int u){Sumt[id[c[u]]] = 0;Redge(u) if (!vis[to = ed[k].to] && to != fa[u]) dfs5(to);
}
void dfs6(int u){D[u] = 0;Redge(u) if (!vis[to = ed[k].to] && to != fa[u]) dfs6(to);
}
void solve(int u){vis[u] = true; Siz[u] = 1;st[top = 1] = c[u]; id[c[u]] = top;Redge(u) if (!vis[to = ed[k].to]){fa[to] = u; dfs1(to);Siz[u] += Siz[to];}now = 0; tot = Siz[u];Redge(u) if (!vis[to = ed[k].to]){now++; dfs2(to);}REP(i,top) D[u] += Sum[i];sum[u] += D[u] + Siz[u];Redge(u) if (!vis[to = ed[k].to]){now++; ttt = 0; tots = Siz[to]; dfs3(to);now++; D[u] -= ttt; dfs4(to);D[u] += ttt; now++; dfs5(to);}D[u] = 0;Redge(u) if (!vis[to = ed[k].to]) dfs6(to);REP(i,top) Vis[i] = Sum[i] = Sumt[i] = id[st[i]] = 0;Redge(u) if (!vis[to = ed[k].to]){N = Siz[to]; F[rt = 0] = INF;getrt(to); solve(rt);}
}
int main(){n = read();REP(i,n) c[i] = read();for (int i = 1; i < n; i++) build(read(),read());F[rt = 0] = INF; N = n;getrt(1); solve(rt);REP(i,n) printf("%lld\n",sum[i]);return 0;
}

转载于:https://www.cnblogs.com/Mychael/p/8921314.html

洛谷P2664 树上游戏 【点分治 + 差分】相关推荐

  1. P2664 树上游戏(点分治/计数题计算贡献/树上差分)

    P2664 树上游戏 对于树上n个点,每个点有不同颜色,求解每个点到其他点的路径上不同颜色个数之和. 首先看到这种树上点对问题,我们可以想到点分治,然后考虑每次分治如何求解答案,本质上就是一个数颜色的 ...

  2. 洛谷 P2197 nim游戏

    洛谷 P2197 nim游戏 题目描述 甲,乙两个人玩Nim取石子游戏. nim游戏的规则是这样的:地上有n堆石子(每堆石子数量小于10000),每人每次可从任意一堆石子里取出任意多枚石子扔掉,可以取 ...

  3. P2664 树上游戏

    P2664 树上游戏 题意: 给一个长度为 n 的颜色序列,定义 s(i,j) 为 i 到 j 的颜色数量.以及 sumi=∑j=1ns(i,j)sum_{i}=\sum_{j=1}^{n}s(i,j ...

  4. 洛谷 P1558 色板游戏

    传送门:洛谷 P1558 色板游戏 算法分析:观察到数据范围:\(1\leq T\leq 30\) ,考虑使用二进制来进行状态压缩 将颜色\(x\)表示为 \(1<<(x-1)\) 即 \ ...

  5. 洛谷 P1129 矩阵游戏

    洛谷 P1129 矩阵游戏 题目链接 题目描述 小 Q 是一个非常聪明的孩子,除了国际象棋,他还很喜欢玩一个电脑益智游戏――矩阵游戏.矩阵游戏在一个 n×n 黑白方阵进行(如同国际象棋一般,只是颜色是 ...

  6. 洛谷 P3041 视频游戏的连击Video Game Combos(AC自动机+拓扑排序+数位DP)

    洛谷 P3041 视频游戏的连击Video Game Combos 难度一般,不过这个数位DP其实应该叫做记忆化搜索 题意:玩游戏时可以通过按键组合打出combo技能:然后是已知N个combo的按键方 ...

  7. 动态规划——洛谷_P1057传球游戏

    题目: 题目描述 上体育课的时候,小蛮的老师经常带着同学们一起做游戏.这次,老师带着同学们一起做传球游戏.游戏规则是这样的:n个同学站成一个圆圈,其中的一个同学手里拿着一个球,当老师吹哨子时开始传球, ...

  8. 洛谷——P1000 超级玛丽游戏

    P1000 超级玛丽游戏 题目背景 本题是洛谷的试机题目,可以帮助了解洛谷的使用. 建议完成本题目后继续尝试P1001.P1008. 另外强烈推荐新用户必读贴 题目描述 超级玛丽是一个非常经典的游戏. ...

  9. 洛谷P1000 超级玛丽游戏C++题解

    首先我们看这道题的题目"超级玛丽游戏",第一道题就让我们写个游戏出来.结果点进去一看,顿时觉得这道题是在开玩笑,本题是洛谷的试机题目,可以帮助了解洛谷的使用. 建议完成本题目后继续 ...

最新文章

  1. 利用Unity3D制作简易2D计算器
  2. javascript装饰者模式
  3. The log scan number (620023:3702:1) passed to log scan in database 'xxxx' is not valid
  4. 写python的笔记本_python笔记本:更改写入的fi
  5. spring-data-jpa动态条件查询
  6. 【数学建模】看了都说好,高温作业专用服装设计拟合函数模型,强烈建议收藏
  7. 应用计算机解数学模型,浅谈数学建模与计算机应用的融合
  8. Ubuntu下mysql可视化_ubuntu上mysql有可视化界面吗 ubuntu mysql 图形界面
  9. laravel 图片流_laravel 做图片的缩略图 踩坑
  10. Linux命令之cat和tac篇
  11. 手机的唯一标识码 php,android手机获取唯一标识的方法
  12. web的标准网页设计与php课后,web网页设计尺寸规范
  13. WebView---android webview组件如何使用 Webview与js交互
  14. IOS大牛的技术人生的经验与心得
  15. 武汉大学1987级计算机专业,武汉大学信息管理学院
  16. 关于前端进行ios配置微信config出现验签失败的问题解决
  17. python中表达式4**0.5的值为_int(4**0.5)
  18. 语音信号处理复习2、语音声学基础
  19. 奥巴马获胜演讲:我们需要的变革
  20. Qt5:TabWidget选项卡

热门文章

  1. C语言 模拟按键操作
  2. Elastic App Search:免费的产品,可提供出色的搜索体验
  3. 域用户如何更改计算机名,加入域后的计算机,怎么改计算机名?
  4. 基于SpringBoot+Vue的酒店管理系统(免费获取源码+项目介绍+运行介绍+运行截图+论文)
  5. 开发好APP了如何上架apple store市场
  6. 洛谷P2678 [NOIP2015 提高组] 跳石头
  7. JOYMY九脉换弹电子烟评测
  8. QWebEngineView 实现网页触屏滑动
  9. Atmel Studio 编译no such file
  10. template <typename T>用法