「LG2664 树上游戏」
这真是一道神仙的一批的题目
定义\(s(i,j)\)表示从点\(i\)到点\(j\)经过的颜色数量
设
\]
求出所有的\(sum_i\)
考虑点分治
对于一个点我们用两种方式来统计其答案
这个点作为分治重心时,分值区域内所有点到这个点贡献
这个点不是分治重心的时候,当前分治区域内其他子树到这个点的贡献
第一种贡献我们很好统计,点分治的时候把所有子树遍历一遍就好了
第二种就需要转换一下思路了,我们不能直接求\(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 树上游戏」的更多相关文章
- LG2664 树上游戏
树上游戏 题目描述 lrb有一棵树,树的每个节点有个颜色.给一个长度为n的颜色序列,定义s(i,j) 为i 到j 的颜色数量.以及 $$sum_i=\sum_{j=1}^ns(i,j)$$ 现在他想让 ...
- 「HAOI2015树上染色」「树形DP」
其实我还不大会树形DP 此题就当练手叭,缕一下思路就好 题目链接 BZOJ4033 题目大意就是给一棵树,对一部分点染成黑色,剩下的为白色,问所有同色点距离之和....... 简明扼要的题意,然额我不 ...
- [LOJ#531]「LibreOJ β Round #5」游戏
[LOJ#531]「LibreOJ β Round #5」游戏 试题描述 LCR 三分钟就解决了问题,她自信地输入了结果-- > -- 正在检查程序 -- > -- 检查通过,正在评估智商 ...
- Vue+WebSocket+ES6+Canvas 制作「你画我猜」小游戏
Vue+WebSocket+ES6+Canvas 制作「你画我猜」小游戏 转载 来源:jrainlau 链接:https://segmentfault.com/a/1190000005804860 项 ...
- LibreOJ #524. 「LibreOJ β Round #4」游戏
二次联通门 : LibreOJ #524. 「LibreOJ β Round #4」游戏 /* LibreOJ #524. 「LibreOJ β Round #4」游戏 找找规律就会发现.. 当有X的 ...
- LibreOJ #6191. 「美团 CodeM 复赛」配对游戏
二次联通门 : LibreOJ #6191. 「美团 CodeM 复赛」配对游戏 /* LibreOJ #6191. 「美团 CodeM 复赛」配对游戏 概率dp */ #include <cs ...
- 「区间DP」「洛谷P1043」数字游戏
「洛谷P1043」数字游戏 日后再写 代码 /*#!/bin/sh dir=$GEDIT_CURRENT_DOCUMENT_DIR name=$GEDIT_CURRENT_DOCUMENT_NAME ...
- LOJ #6192. 「美团 CodeM 复赛」城市网络 (树上倍增)
#6192. 「美团 CodeM 复赛」城市网络 内存限制:64 MiB 时间限制:500 ms 标准输入输出 题目描述 有一个树状的城市网络(即 nnn 个城市由 n−1n-1n−1 条道路连接 ...
- Note -「圆方树」学习笔记
目录 圆方树的定义 圆方树的构造 实现 细节 圆方树的运用 「BZOJ 3331」压力 「洛谷 P4320」道路相遇 「APIO 2018」「洛谷 P4630」铁人两项 「CF 487E」Touris ...
随机推荐
- [转]Entity Framework Sprocs with Multiple Result Sets
本文转自:https://msdn.microsoft.com/en-us/data/jj691402.aspx Entity Framework Sprocs with Multiple Resul ...
- Cannot find module 'object-keys' 的解决办法
把node_modules文件夹删除,重新cnpm install安装node_modules就好了.
- Expression Blend实例中文教程(7) - 动画基础快速入门Animation
通过前面文章学习,已经对Blend的开发界面,以及控件有了初步的认识.本文将讲述Blend的一个核心功能,动画设计.大家也许注意到,从开篇到现在,所有的文章都是属于快速入门,是因为这些文章,都是我曾经 ...
- C#,动态加载DLL,通过反射,调用参数,方法,窗体
.net中常会用到动态加载DLL,而DLL中可能包含各种参数.方法.窗体,如何来调用动态加载这些参数.方法.窗体呢? 在C#中,我们要使用反射,首先要搞清楚以下命名空间中几个类的关系: System. ...
- ASP.NET Visual Studio2010 发布Web网站问题详解
今天研究了一下如何发布web网站,之前总是没耐心,遇到点问题就没心情搞了,今天总算有点耐心搞明白了.其实遇到的问题还是挺多的,网上也没有太全的解释,所以结合自己还有别人的方法进行一下总结. 环境:Wi ...
- [android] 练习viewpagerindicator的使用(二)
主要还是想实现滑动的tab切换效果 MainActivity.java package com.example.csdn; import com.viewpagerindicator.TabPageI ...
- Intellij IDEA 各种乱码解决方案 posted @ 2017-06-23 15:31:06
一次解决所有问题,只需做配置文件的修改即可 解决方案: 在 IntelliJ IDEA 2016.1\bin\idea64.exe.vmoptions Intell ...
- hdu 4003 Find Metal Mineral 树形dp ,*****
Find Metal Mineral Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65768/65768 K (Java/Other ...
- 多实例部署多个tomcat
注意点: 1.多实例tomcat的更新维护,需要考虑如何能“优雅”地对所有实例进行升级: 2.尽量不要影响应用程序,在更新tomcat时,一不小心就把conf目录等全部覆盖,所以尽量要把配置文件和安装 ...
- 使用mpvue搭建一个初始小程序
1. 初始化一个 mpvue 项目 现代前端开发框架和环境都是需要 Node.js 的,如果没有的话,请先下载 nodejs 并安装. 然后打开命令行工具: # 1. 先检查下 Node.js 是否安 ...