题目

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

定义\(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. js验证港澳居民通行证号码是否合规

    需求:最近要做实名验证的功能,但是验证我们要验证严谨一点,参考了网上关于验证港澳居民通行证号码的代码,总结一下. 代码: function checkHKMacao(code){ var tip = ...

  2. [转]NLog 自定义字段 写入 oracle

    本文转自:http://www.cnblogs.com/skyapplezhao/p/5690695.html 1.通过Nuget安装NLog 下载,简单入门 请参照 我刚才转的几篇文章,下面我直接贴 ...

  3. [android] 练习使用ListView(三)

    解决OOM和图片乱序问题 package com.android.test; import java.io.InputStream; import java.net.HttpURLConnection ...

  4. 学会Markdown,写博客不愁

    前言 Markdown是一种轻量级的标记语言,有John Gruber以及Aaron Hillel Swartz一起编写.Aaron Hillel Swartz是一个极富传奇的黑客,有兴趣可以看看他的 ...

  5. springboot项目作为war包运行

    一.首先是pom文件中设置打成war包 < packaging>war< /packaging> 二.然后是修改依赖: <dependency> <group ...

  6. spring boot 定时任务

    定时任务实现方式 三种: 1) Java自带的java.util.Timer类,这个类允许你调度一个java.util.TimerTask任务. 最早的时候就是这样写定时任务的. 2) 开源的第三方框 ...

  7. Bazaar 版本控制工具

    Bazaar是一个分布式的版本控制系统,它发布在GPL许可协议之下,并可用于Windows.GNU/Linux.UNIX以及Mac OS系统.Bazaar由Canonical公司赞助,目前已服务于Sa ...

  8. vc++返回模块路径

    #include "stdafx.h"#include <Windows.h>#include <string.h>const int MAXPATHLEN ...

  9. 移动端适配(2)——viewport适配

    通过viewport来适配 <script> (function(){ var w=window.screen.width; console.log(w);//获取屏幕尺寸 var tar ...

  10. Django Cookie于Session

    一.Cookie与Session由来 因为Http协议的特性,每一次来自用户浏览器的请求都是无状态且独立的,通俗地说,就是无法保存用户状态,后台服务器根本就不知道当前请求和以前及以后请求是否来自同一用 ...