题目链接:https://www.luogu.org/problem/P2664

题意:给定一颗带点权的树,结点数n<=1e5,点权<=1e5,用s(i,j)表示从i到j的路径上不同点权数,ans[i]=sum(s(i,j))。求ans数组。

思路:

  继续肝淀粉质,太难了。

  涉及到树上点对,且nlogn满足时,就可以考虑考虑点分治了。所以回到这题,我们需要在O(n)时间内统计出以p为根节点的子树上所有节点对p的贡献,以及对所有经过p的路径的贡献。

  

  我们通过dfs1得到这些贡献值和他们的和sum,显然子树上所有节点对p的贡献就是sum,即ans[p]+=sum。

  

  另外,sum、ans数组和color数组需要用LL,在这wa了两发。

AC代码:

#include<cstdio>
#include<algorithm>
#include<cctype>
using namespace std; inline int read(){
int x=,f=;char c=;
while(!isdigit(c)){f|=c=='-';c=getchar();}
while(isdigit(c)) x=(x<<)+(x<<)+(c^),c=getchar();
return f?-x:x;
} typedef long long LL;
const int maxn=1e5+;
const int inf=0x3f3f3f3f;
struct node{
int v,nex;
}edge[maxn<<]; int n,c[maxn],ct,head[maxn],Min,root,size,sz[maxn],mson[maxn];
int cnt[maxn],num,t,vis[maxn];
LL ans[maxn],color[maxn],sum; void adde(int u,int v){
edge[++ct].v=v;
edge[ct].nex=head[u];
head[u]=ct;
} void getroot(int u,int fa){
sz[u]=,mson[u]=;
for(int i=head[u];i;i=edge[i].nex){
int v=edge[i].v;
if(v==fa||vis[v]) continue;
getroot(v,u);
sz[u]+=sz[v];
if(sz[v]>mson[u]) mson[u]=sz[v];
}
if(size-sz[u]>mson[u]) mson[u]=size-sz[u];
if(mson[u]<Min) Min=mson[u],root=u;
} void dfs1(int u,int fa){
sz[u]=;
++cnt[c[u]];
for(int i=head[u];i;i=edge[i].nex){
int v=edge[i].v;
if(v==fa||vis[v]) continue;
dfs1(v,u);
sz[u]+=sz[v];
}
if(cnt[c[u]]==){
sum+=sz[u];
color[c[u]]+=sz[u];
}
--cnt[c[u]];
} void change(int u,int fa,int f){
++cnt[c[u]];
for(int i=head[u];i;i=edge[i].nex){
int v=edge[i].v;
if(v==fa||vis[v]) continue;
change(v,u,f);
}
if(cnt[c[u]]==){
sum+=sz[u]*f;
color[c[u]]+=sz[u]*f;
}
--cnt[c[u]];
} void dfs2(int u,int fa){
++cnt[c[u]];
if(cnt[c[u]]==){
sum-=color[c[u]];
++num;
}
ans[u]+=sum+num*t;
for(int i=head[u];i;i=edge[i].nex){
int v=edge[i].v;
if(vis[v]||v==fa) continue;
dfs2(v,u);
}
if(cnt[c[u]]==){
sum+=color[c[u]];
--num;
}
--cnt[c[u]];
} void clear(int u,int fa){
cnt[c[u]]=color[c[u]]=;
for(int i=head[u];i;i=edge[i].nex){
int v=edge[i].v;
if(vis[v]||v==fa) continue;
clear(v,u);
}
} void solve(int u){
dfs1(u,);
ans[u]+=sum;
for(int i=head[u];i;i=edge[i].nex){
int v=edge[i].v;
if(vis[v]) continue;
++cnt[c[u]],sum-=sz[v],color[c[u]]-=sz[v];
change(v,u,-);--cnt[c[u]];
t=sz[u]-sz[v];
dfs2(v,u);
++cnt[c[u]],sum+=sz[v],color[c[u]]+=sz[v];
change(v,u,);--cnt[c[u]];
}
sum=,num=;
clear(u,);
} void fenzhi(int u){
vis[u]=;
solve(u);
for(int i=head[u];i;i=edge[i].nex){
int v=edge[i].v;
if(vis[v]) continue;
Min=inf,root=,size=sz[v];
getroot(v,);
fenzhi(root);
}
} int main(){
n=read();
for(int i=;i<=n;++i)
c[i]=read();
for(int i=;i<n;++i){
int u=read(),v=read();
adde(u,v);
adde(v,u);
}
Min=inf,root=,size=n;
getroot(,);
fenzhi(root);
for(int i=;i<=n;++i)
printf("%lld\n",ans[i]);
return ;
}

  

luoguP2664树上游戏(点分治)的更多相关文章

  1. 【点分治】luoguP2664 树上游戏

    应该是一道中等难度的点分?麻烦在一些细节. 题目描述 lrb有一棵树,树的每个节点有个颜色.给一个长度为n的颜色序列,定义s(i,j) 为i 到j 的颜色数量.以及 现在他想让你求出所有的sum[i] ...

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

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

  3. 洛谷P2664 树上游戏——点分治

    原题链接 被点分治虐的心态爆炸了 题解 发现直接统计路径上的颜色数量很难,考虑转化一下统计方式.对于某一种颜色\(c\),它对一个点的贡献为从这个点出发且包含这种颜色的路径条数. 于是我们先点分一下, ...

  4. luoguP2664 树上游戏

    https://www.luogu.org/problemnew/show/P2664 考虑对于每种颜色包含的点和这些点的子节点建出虚树,发现只要将一个联通块中的东西 Dp + 差分一下就行了 当然要 ...

  5. 【洛谷P2664】 树上游戏 点分治

    code: #include <bits/stdc++.h> #define N 200009 #define ll long long #define setIO(s) freopen( ...

  6. 【Luogu2664】树上游戏(点分治)

    [Luogu2664]树上游戏(点分治) 题面 洛谷 题解 很好的一道点分治题. 首先直接点分治,考虑过每个分治重心的链的贡献. 我们从分治重心开始找每种颜色,强制令一种颜色只在其到分治重心的链上第一 ...

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

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

  8. P2664 树上游戏

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

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

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

随机推荐

  1. linux 搭建 jenkins 前端自动构建时,老是提示 sh: vue-cli-service: command not found

    如题. 在 shell 里面执行  env 发现一个   NODE_ENV=production  的环境变量,是这个东西的原因. 通过  unset NODE_ENV  命令去掉这个环境变量就可以了 ...

  2. ubuntu彻底卸载mysql并且重新安装

    环境: root@ubuntu:/usr/local/mysql/data# uname -a Linux ubuntu 4.4.0-87-generic #110-Ubuntu SMP Tue Ju ...

  3. [Linux]安装kali虚拟机后忘记root密码

    1. 登录时,按e进入编辑模式 2. 编辑模式 修改 ro 修改为 rw 添加 init=/bin/bash 修改完按 F10 3. 选择recovery mode 回车 4.输入命令passwd 设 ...

  4. Jmeter工具做接口测试

    一.安装Jmeter 1.安装JDK ①下载jdk,到官网下载jdk,地址:http://jmeter.apache.org/download_jmeter.cgi ② 安装jdk(Oracle官网下 ...

  5. 【Redis 设置Redis使用LRU算法】

    转自:http://ifeve.com/redis-lru/ 本文将介绍Redis在生产环境中使用的Redis的LRU策略,以及自己动手实现的LRU算法(php) 1.设置Redis使用LRU算法 L ...

  6. LeetCode205----同构字符串

    给定两个字符串 s 和 t,判断它们是否是同构的. 如果 s 中的字符可以被替换得到 t ,那么这两个字符串是同构的. 所有出现的字符都必须用另一个字符替换,同时保留字符的顺序.两个字符不能映射到同一 ...

  7. PHPStorm2017去掉函数参数提示

    今天升级到 PHPStorm 2017.1 发现增加了好些新功能, 有个默认开启的参数名和类型提示功能, 虽然功能挺强大的, 不过我用不着, 还是关掉的好, 有同样需求的同学可以看看 例子比较特殊这么 ...

  8. Android APP切换到后台接收不到推送消息

    1.   Android端进程被杀死后,目前自带的保护后台接收消息活跃机制.暂时没有什么好的机制保持任何情况下都活跃 android原生系统用home键杀进程可以起来,如果是强行停止就只能用户自己手动 ...

  9. centos7 下安装和配置 mongodb (重点)

    1.下载安装包 wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-4.0.4.tgz 2.解压 tar -zxvf m ...

  10. Android Dalvik、ART及APK编译过程

    0.1 先对Dalvik以及ART做简单介绍: 什么是Dalvik: Dalvik是Google公司自己设计用于Android平台的Java虚拟机.dex格式是专为Dalvik应用设计的一种压缩格式, ...