P2664 树上游戏
P2664 树上游戏
https://www.luogu.org/problemnew/show/P2664
分析:
点分治。
首先关于答案的统计转化成计算每个颜色的贡献。
1、计算从根出发的路径的答案:如果某一个颜色是从根到这个点的链上的第一次出现的,那么这个颜色会对根产生siz[x]个贡献。(根连向它子树的任意一个点的路径都包含这个颜色)。
2、计算子树内每个点过根的路径答案:记录一个数组sum[i],表示从根出发包含颜色i的路径的条数(在1中,找到一个第一次出现的颜色,加上这个点的siz即可)。然后假设当前点是x,根为z,x所在的子树为y。x->z的路径上,出现的颜色为Num,那么这Num个颜色由于已经在到根的路径上有了,那么随便选择其它子树内的点构成的路径都包含了这个颜色,贡献为(siz[z]-siz[y])*Num;未出现的颜色的贡献:在y子树外计算多少个点与x构成的路径,包含这个颜色。那么可以sum数组的和得到,但是其中包含的y子树的路径,所以一开始要先减掉。
代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<iostream>
#include<cctype>
#include<set>
#include<vector>
#include<queue>
#include<map>
#define fi(s) freopen(s,"r",stdin);
#define fo(s) freopen(s,"w",stdout);
using namespace std;
typedef long long LL; inline int read() {
int x=,f=;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-;
for(;isdigit(ch);ch=getchar())x=x*+ch-'';return x*f;
} const int INF = 1e9;
const int N = ; int head[N], nxt[N << ], to[N << ], En;
int col[N], siz[N], sk[N];
LL ans[N], cnt[N], sum[N], Sum, Num;
bool vis[N];
int Size, Mn, Root, top;
// cnt[i] 颜色i出现的次数,sum[i]以根为起点,包含颜色i的路径条数,Sum为sum[i]的和。 void add_edge(int u,int v) {
++En; to[En] = v; nxt[En] = head[u]; head[u] = En;
++En; to[En] = u; nxt[En] = head[v]; head[v] = En;
} void getroot(int u,int fa) {
siz[u] = ;
int cnt = ;
for (int i=head[u]; i; i=nxt[i]) {
int v = to[i];
if (v == fa || vis[v]) continue; // vis[v]!!!
getroot(v, u);
siz[u] += siz[v];
cnt = max(cnt, siz[v]);
}
cnt = max(cnt, Size - siz[u]);
if (cnt < Mn) { Mn = cnt, Root = u; }
} void dfs1(int u,int fa) { // 计算siz,sum,以根为起点的答案。
siz[u] = ; cnt[col[u]] ++;
for (int i=head[u]; i; i=nxt[i])
if (!vis[to[i]] && to[i] != fa)
dfs1(to[i], u), siz[u] += siz[to[i]];
if (cnt[col[u]] == )
Sum += siz[u], sum[col[u]] += siz[u], sk[++top] = col[u];
cnt[col[u]] --;
} void dfs2(int u,int fa) { // 计算子树内每个点 过根的所有路径的答案。
cnt[col[u]] ++;
if (cnt[col[u]] == )
Num ++, Sum -= sum[col[u]]; // 只考虑过根的路径,Num记录这个点到根的路径第一次出现的颜色的个数
ans[u] += Num * Size + Sum;
// 这些Num个颜色因为到根的路径上已经有这个颜色了,所以和其他的点任意组合的路径都满足有这个颜色;Sum为除了Num个颜色以外的颜色的贡献
for (int i=head[u]; i; i=nxt[i])
if (!vis[to[i]] && to[i] != fa) dfs2(to[i], u);
if (cnt[col[u]] == )
Num --, Sum += sum[col[u]];
cnt[col[u]] --;
} void Modify(int u,int fa,int p) {
cnt[col[u]] ++;
for (int i=head[u]; i; i=nxt[i])
if (!vis[to[i]] && to[i] != fa) Modify(to[i], u, p);
if (cnt[col[u]] == )
Sum += siz[u] * p, sum[col[u]] += siz[u] * p;
cnt[col[u]] --;
}
void change(int u,int fa,int p) {
Sum += siz[u] * p, sum[col[fa]] += siz[u] * p; // sum[col[fa]]=siz[fa],现在应该减去这棵子树
cnt[col[fa]] ++; Modify(u, fa, p); cnt[col[fa]] --;
} void Calc(int u) {
top = ; dfs1(u, ); ans[u] += Sum; // 计算子树内每个点的siz,sum,以根为起点的答案。
for (int i=head[u]; i; i=nxt[i]) {
int v = to[i];
if (vis[v]) continue;
change(v, u, -); // 把这棵子树的贡献减去
Size = siz[u] - siz[v]; dfs2(v, u); // Size = siz[v] !!!,计算子树内的每个点答案。
change(v, u, ); // 加回来
}
Num = Sum = ;
for (int i=; i<=top; ++i) cnt[sk[i]] = sum[sk[i]] = ;
}
void solve(int u) {
Calc(u); vis[u] = true;
for (int i=head[u]; i; i=nxt[i]) {
int v = to[i];
if (vis[v]) continue;
Size = siz[v], Mn = INF;
getroot(v, );
solve(Root);
}
} int main() {
int n = read();
for (int i=; i<=n; ++i) col[i] = read();
for (int i=; i<n; ++i) {
int x = read(), y = read();
add_edge(x, y);
}
Size = n, Mn = 1e9;
getroot(, );
solve(Root);
for (int i=; i<=n; ++i) printf("%lld\n",ans[i]);
return ;
}
P2664 树上游戏的更多相关文章
- 洛谷 P2664 树上游戏 解题报告
P2664 树上游戏 题目描述 \(\text{lrb}\)有一棵树,树的每个节点有个颜色.给一个长度为\(n\)的颜色序列,定义\(s(i,j)\) 为 \(i\) 到 \(j\) 的颜色数量.以及 ...
- Luogu P2664 树上游戏 dfs+树上统计
题目: P2664 树上游戏 分析: 本来是练习点分治的时候看到了这道题.无意中发现题解中有一种方法可以O(N)解决这道题,就去膜拜了一下. 这个方法是,假如对于某一种颜色,将所有这种颜色的点全部删去 ...
- ●洛谷P2664 树上游戏
题链: https://www.luogu.org/problemnew/show/P2664题解: 扫描线,线段树维护区间覆盖 https://www.luogu.org/blog/ZJ75211/ ...
- 洛谷P2664 树上游戏(点分治)
传送门 题解 因为一个sb错误调了一个晚上……鬼晓得我为什么$solve(rt)$会写成$solve(v)$啊!!!一个$O(logn)$被我硬生生写成$O(n)$了竟然还能过$5$个点……话说还一直 ...
- 洛谷P2664 树上游戏
https://www.luogu.org/problemnew/show/P2664 #include<cstdio> #include<algorithm> #includ ...
- [LuoGu]P2664 树上游戏
Portal 这题真的好. 看到树上路径, 脑子里就要点分治 这一题对于每个点都要计算一遍, 如果暴算实在不好算, 这样我们就可以考虑算贡献. 直接计算每种颜色的贡献. 因为一条过重心的路径中, 可能 ...
- 洛谷P2664 树上游戏(点分治)
题意 题目链接 Sol 神仙题..Orz yyb 考虑点分治,那么每次我们只需要统计以当前点为\(LCA\)的点对之间的贡献以及\(LCA\)到所有点的贡献. 一个很神仙的思路是,对于任意两个点对的路 ...
- 【刷题】洛谷 P2664 树上游戏
题目描述 lrb有一棵树,树的每个节点有个颜色.给一个长度为n的颜色序列,定义s(i,j) 为i 到j 的颜色数量.以及 \[sum_i=\sum_{j=1}^ns(i,j)\] 现在他想让你求出所有 ...
- 洛谷P2664 树上游戏 【点分治 + 差分】
题目 lrb有一棵树,树的每个节点有个颜色.给一个长度为n的颜色序列,定义s(i,j) 为i 到j 的颜色数量.以及 现在他想让你求出所有的sum[i] 输入格式 第一行为一个整数n,表示树节点的数量 ...
随机推荐
- 使用Swagger处理Api的显示与隐藏
一.在SwaggerConfig.cs中配置如下: c.DocumentFilter<ShowApiFilter>(); c.DocumentFilter<HideApiFilter ...
- mongodb启动和关闭
mongodb的启动 mongod --dbpath=/data/mongodb/data --logpath=/data/mongodb/log/33988.log --port 33988 --f ...
- 关于项目中的DAL数据接入层架构设计
摘要:项目中对关系型数据库的接入再寻常不过,也有海量的ORM工具可供选择,一个一般性的DAL数据接入层的结构却大同小异,这里就分享一下使用Hibernate.Spring.Hessian这三大工具对D ...
- hbase hfilev2
版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/u014393917/article/details/25508809 HFileV2文件 HFile ...
- 下载安装Redis+使用
Window 下安装 第一步:安装 下载地址:https://github.com/MSOpenTech/redis/releases 第二步:解压(盘符) 第三步:打开一个 cmd 窗口 使用 cd ...
- 【题解】洛谷P1074 [NOIP2009TG] 靶形数独(DFS+剪枝)
洛谷P1074:https://www.luogu.org/problemnew/show/P1074 思路 这道题一看就是DFS 打一个分数表方便后面算分 我用x y z数组分别表示行 列 宫 是否 ...
- 在CentOS 7上安装Docker环境
官网文档:https://docs.docker.com/engine/installation/linux/centos/ ,本文大部分是照搬官方文档写的,如果你英文还不错,那么就直接移步官方文档吧 ...
- KMP初探
最近在做字符串匹配,沉迷于indexof无法自拔,但是考虑到大数据处理的时间复杂度,决定研究一波KMP. 在这我就不讲什么原理了,转自: https://www.cnblogs.com/zhangti ...
- 搭建Extjs框架(二)
搭建Extjs 框架 二.编写入口文件 app.js,配置extjs 组件\视图文件路径 并将app.js引入index.html 在app.js中指定一些文件的路径,Extjs页面的起始 ...
- MySQL(mariadb)多实例应用与多实例主从复制
MySQL多实例 mysql多实例,简单理解就是在一台服务器上,mysql服务开启多个不同的端口(如3306.3307,3308),运行多个服务进程.这些 mysql 服务进程通过不同的 socket ...