题目

这真是一道神仙的一批的题目

定义\(s(i,j)\)表示从点\(i\)到点\(j\)经过的颜色数量

\[sum_i=\sum_{j=1}^ns(i,j)
\]

求出所有的\(sum_i\)

考虑点分治

对于一个点我们用两种方式来统计其答案

  1. 这个点作为分治重心时,分值区域内所有点到这个点贡献

  2. 这个点不是分治重心的时候,当前分治区域内其他子树到这个点的贡献

第一种贡献我们很好统计,点分治的时候把所有子树遍历一遍就好了

第二种就需要转换一下思路了,我们不能直接求\(s(i,j)\)了,我们应该求某一种颜色一共被数了多少次

我们开一个桶\(tax\),\(tax[i]\)表示\(i\)这种颜色控制的大小一共是多少,也就是这个颜色会被多少个终点数到,我们可以通过提前遍历好所有子树得到这个信息

每次进入一棵子树的时候,提前减掉这个子树的贡献,之后进入子树\(dfs\)就好了,如果一旦出现一种新颜色,显然这种颜色会被当前分治区域内所有点数上,更改一下贡献即可

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#define maxn 100005
#define re register
#define inf 99999999
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read() {
int x=0;char c=getchar();while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
struct E{int v,nxt;}e[maxn<<1];
int col[maxn],head[maxn],vis[maxn],sum[maxn],mx[maxn];
int f[maxn],tax[maxn],d[maxn],st[maxn],tmp[maxn];
int num,n,m,now,S,rt,top;
LL ans,Ans[maxn],res;
std::vector<int> v[maxn],c[maxn];
inline void add(int x,int y) {e[++num].v=y;e[num].nxt=head[x];head[x]=num;}
void getroot(int x,int fa) {
sum[x]=1,mx[x]=0;
for(re int i=head[x];i;i=e[i].nxt) {
if(vis[e[i].v]||e[i].v==fa) continue;
getroot(e[i].v,x);
sum[x]+=sum[e[i].v],mx[x]=max(mx[x],sum[e[i].v]);
}
mx[x]=max(mx[x],S-sum[x]);
if(mx[x]<now) now=mx[x],rt=x;
}
void getdis(int x,int fa,int now,int t) {
if(!f[col[x]]) now++;
if(!tmp[col[x]]) st[++top]=col[x];
tmp[col[x]]=1;sum[x]=1;f[col[x]]++;Ans[t]+=now;
for(re int i=head[x];i;i=e[i].nxt) {
if(vis[e[i].v]||e[i].v==fa) continue;
getdis(e[i].v,x,now,t);sum[x]+=sum[e[i].v];
}
if(f[col[x]]==1) d[col[x]]+=sum[x];
f[col[x]]--;
}
void find(int x,int fa) {
if(!f[col[x]]) ans-=tax[col[x]],ans+=res;
Ans[x]+=ans;f[col[x]]++;
for(re int i=head[x];i;i=e[i].nxt) {
if(vis[e[i].v]||e[i].v==fa) continue;
find(e[i].v,x);
}
if(f[col[x]]==1) ans-=res,ans+=tax[col[x]];
f[col[x]]--;
}
void dfs(int x) {
vis[x]=1;ans=0;f[col[x]]=1;
for(re int i=head[x];i;i=e[i].nxt) {
if(vis[e[i].v]) continue;
top=0;getdis(e[i].v,0,1,x);
for(re int j=1;j<=top;j++)
if(st[j]!=col[x]) v[e[i].v].push_back(d[st[j]]),c[e[i].v].push_back(st[j]);
for(re int j=1;j<=top;j++)
if(st[j]!=col[x]) tax[st[j]]+=d[st[j]],ans+=d[st[j]];
for(re int j=1;j<=top;j++) tmp[st[j]]=0,d[st[j]]=0;
}
f[col[x]]=0;
ans+=S,tax[col[x]]=S;
for(re int i=head[x];i;i=e[i].nxt) {
if(vis[e[i].v]) continue;
res=S-sum[e[i].v];
ans-=sum[e[i].v],tax[col[x]]-=sum[e[i].v];
for(re int j=0;j<v[e[i].v].size();j++)
ans-=v[e[i].v][j],tax[c[e[i].v][j]]-=v[e[i].v][j];
find(e[i].v,0);
for(re int j=0;j<v[e[i].v].size();j++)
ans+=v[e[i].v][j],tax[c[e[i].v][j]]+=v[e[i].v][j];
ans+=sum[e[i].v],tax[col[x]]+=sum[e[i].v];
}
for(re int i=head[x];i;i=e[i].nxt) {
if(vis[e[i].v]) continue;
for(re int j=0;j<v[e[i].v].size();j++)
tax[c[e[i].v][j]]-=v[e[i].v][j];
v[e[i].v].clear(),c[e[i].v].clear();
}
tax[col[x]]=0;
for(re int i=head[x];i;i=e[i].nxt) {
if(vis[e[i].v]) continue;
now=inf,S=sum[e[i].v],getroot(e[i].v,0),dfs(rt);
}
}
int main() {
n=read();int x,y;
for(re int i=1;i<=n;i++) col[i]=read();
for(re int i=1;i<n;i++) x=read(),y=read(),add(x,y),add(y,x);
S=n,now=inf,getroot(1,0);dfs(rt);
for(re int i=1;i<=n;i++) printf("%lld\n",Ans[i]+1ll);
return 0;
}

「LG2664 树上游戏」的更多相关文章

  1. LG2664 树上游戏

    树上游戏 题目描述 lrb有一棵树,树的每个节点有个颜色.给一个长度为n的颜色序列,定义s(i,j) 为i 到j 的颜色数量.以及 $$sum_i=\sum_{j=1}^ns(i,j)$$ 现在他想让 ...

  2. 「HAOI2015树上染色」「树形DP」

    其实我还不大会树形DP 此题就当练手叭,缕一下思路就好 题目链接 BZOJ4033 题目大意就是给一棵树,对一部分点染成黑色,剩下的为白色,问所有同色点距离之和....... 简明扼要的题意,然额我不 ...

  3. [LOJ#531]「LibreOJ β Round #5」游戏

    [LOJ#531]「LibreOJ β Round #5」游戏 试题描述 LCR 三分钟就解决了问题,她自信地输入了结果-- > -- 正在检查程序 -- > -- 检查通过,正在评估智商 ...

  4. Vue+WebSocket+ES6+Canvas 制作「你画我猜」小游戏

    Vue+WebSocket+ES6+Canvas 制作「你画我猜」小游戏 转载 来源:jrainlau 链接:https://segmentfault.com/a/1190000005804860 项 ...

  5. LibreOJ #524. 「LibreOJ β Round #4」游戏

    二次联通门 : LibreOJ #524. 「LibreOJ β Round #4」游戏 /* LibreOJ #524. 「LibreOJ β Round #4」游戏 找找规律就会发现.. 当有X的 ...

  6. LibreOJ #6191. 「美团 CodeM 复赛」配对游戏

    二次联通门 : LibreOJ #6191. 「美团 CodeM 复赛」配对游戏 /* LibreOJ #6191. 「美团 CodeM 复赛」配对游戏 概率dp */ #include <cs ...

  7. 「区间DP」「洛谷P1043」数字游戏

    「洛谷P1043」数字游戏 日后再写 代码 /*#!/bin/sh dir=$GEDIT_CURRENT_DOCUMENT_DIR name=$GEDIT_CURRENT_DOCUMENT_NAME ...

  8. LOJ #6192. 「美团 CodeM 复赛」城市网络 (树上倍增)

    #6192. 「美团 CodeM 复赛」城市网络 内存限制:64 MiB 时间限制:500 ms 标准输入输出   题目描述 有一个树状的城市网络(即 nnn 个城市由 n−1n-1n−1 条道路连接 ...

  9. Note -「圆方树」学习笔记

    目录 圆方树的定义 圆方树的构造 实现 细节 圆方树的运用 「BZOJ 3331」压力 「洛谷 P4320」道路相遇 「APIO 2018」「洛谷 P4630」铁人两项 「CF 487E」Touris ...

随机推荐

  1. 架构实战项目心得(十四):spring-boot结合Swagger2构建RESTful API测试体系

    一.添加依赖: <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-s ...

  2. php根据IP获取所在省份-百度api接口

    这里用的file_put_contents,你也可以用别的,直接怼代码: //拼接传递的参数 $getData = array( 'query' => '127.0.0.1', 'resourc ...

  3. 在centos linux上安装docker

    前置条件 64-bit 系统 kernel 3.10+ 1.检查内核版本,返回的值大于3.10即可. $ uname -r 2.确保yum是最新的 $ yum update 3.安装 Docker y ...

  4. 基于easyUI实现权限管理系统(四)——用户管理

    此文章是基于 EasyUI+Knockout实现经典表单的查看.编辑 一. 相关文件介绍 1. user.jsp:用户管理界面 <!DOCTYPE html PUBLIC "-//W3 ...

  5. browserslist 目标浏览器配置表

    为什么需要: 根据提供的目标浏览器的环境来,智能添加css前缀,js的polyfill垫片,来兼容旧版本浏览器,而不是一股脑的添加.避免不必要的兼容代码,以提高代码的编译质量. 共享使用browser ...

  6. JavaScript AMD 与CMD的代码区别

    1:CMD 依赖就近 define(function(require,export) { var b =1; var a = require("../a"); a.dosometh ...

  7. base64编码 的 图片 另存为下载

    功能描述: 有一段base64字符串的图片,将其保存下载为png图片! 可以:  直接 a 链接下载:  <a id="tttt" download="1.jpg& ...

  8. cookie结合js 实现记住的拖拽

    哈喽!!!我胡汉三又回来啦!!!有木有记挂挪啊!咱们今天说一个 cookie结合JS的小案例哦! 话不多说直接上代码: <!DOCTYPE html> <html> <h ...

  9. Codeforces Round #415 (Div. 2) B. Summer sell-off

    B. Summer sell-off time limit per test   1 second memory limit per test   256 megabytes   Summer hol ...

  10. Git学习-Git时光机之版本回退(二)

    Git,是Linus花了两周时间用C写的一个分布式版本控制系统.牛人该怎么定义? 零.结论先行 倒叙总结一下: HEAD指向的版本就是当前版本,因此,Git允许我们在版本的历史之间穿梭,使用命令git ...