• 一道点分难题
  • 首先很自然的想法就是每种颜色的贡献可以分开计算,然后如果你会虚树就可以直接做了
  • 点分也差不多,考虑每个分治重心的子树对它的贡献以及它对它子树的贡献
  • 首先,处理一个\(cnt\)数组,\(cnt[i]\)表示从重心出发有多少条包含i颜色的路径,具体做法就是dfs,当该颜色第一次出现时就加上当前子树的size,还要记录子树中出现了哪几种颜色,不能每次都枚举所有颜色,显然,对分治重心的贡献就是\(\sum cnt[i]\).
  • 接下来计算分治重心对子树内的贡献,比较麻烦,首先对每颗子树求出ct,定义与\(cnt\)一样,每次令\(cnt[cl[i]]=cnt[cl[i]]-ct[cl[i]]\)就是除该子树以外的有颜色i的路径数,还要特别地把根的颜色在该子树内出现次数减去,也就是减去该子树的size,设分治重心除该子树以外的的点数为\(path\),\(tot\)为现在\(cnt\)数组的和,递归该子树,对于每个节点要加上tot,如果该节点颜色在递归中第一次出现,则产生贡献\(path-cnt[cl]\),同时该贡献还会影响其子树,所以将该贡献在递归是下传即可,最后清空数组,继续分治即可
#include<bits/stdc++.h>
using namespace std;
typedef int sign;
typedef long long ll;
#define For(i,a,b) for(register sign i=(sign)a;i<=(sign)b;++i)
#define Fordown(i,a,b) for(register sign i=(sign)a;i>=(sign)b;--i)
const int N=1e5+5;
bool cmax(sign &a,sign b){return (a<b)?a=b,1:0;}
bool cmin(sign &a,sign b){return (a>b)?a=b,1:0;}
template<typename T>T read()
{
T ans=0,f=1;
char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch-'0'),ch=getchar();
return ans*f;
}
template<typename T>void write(T x,char y)
{
if(x==0)
{
putchar('0');putchar(y);
return;
}
if(x<0)
{
putchar('-');
x=-x;
}
static char wr[20];
int top=0;
for(;x;x/=10)wr[++top]=x%10+'0';
while(top)putchar(wr[top--]);
putchar(y);
}
void file()
{
#ifndef ONLINE_JUDGE
freopen("2664.in","r",stdin);
freopen("2664.out","w",stdout);
#endif
}
int n,c[N];
int head[N],tt,nex[N<<1],to[N<<1];
void add(int x,int y)
{
++tt,to[tt]=y,nex[tt]=head[x],head[x]=tt;
}
void input()
{
int x,y;
n=read<int>();
For(i,1,n)c[i]=read<int>();
For(i,2,n)
{
x=read<int>(),y=read<int>();
add(x,y),add(y,x);
}
}
const int inf=0x3f3f3f3f;
int sum,size[N],root,min_sz;
bool ban[N];
#define rg register
void get_root(int u,int pre)
{
int mx=0;
for(rg int i=head[u];i;i=nex[i])
{
if(to[i]==pre||ban[to[i]])continue;
get_root(to[i],u);
cmax(mx,size[to[i]]);
}
cmax(mx,sum-size[u]);
if(mx<min_sz)min_sz=mx,root=u;
}
void get_sz(int u,int pre)
{
size[u]=1;
for(rg int i=head[u];i;i=nex[i])
{
if(to[i]==pre||ban[to[i]])continue;
get_sz(to[i],u);
size[u]+=size[to[i]];
}
}
bool apper[N];
int cl[N],col[N],num[N],top,tp;
ll tot,cnt[N],ct[N],ans[N],cct[N];
void dfs(int u,int pre,ll *cnt)
{
if(!apper[c[u]])col[++top]=c[u],apper[c[u]]=true;
if(++num[c[u]]==1)cnt[c[u]]+=size[u];
for(rg int i=head[u];i;i=nex[i])
{
if(to[i]==pre||ban[to[i]])continue;
dfs(to[i],u,cnt);
}
--num[c[u]];
}
ll path;
void modify(int u,int pre,ll las)
{
ll tag=las;
if(++num[c[u]]==1)tag+=path-cnt[c[u]];
ans[u]+=tag+tot;
for(rg int i=head[u];i;i=nex[i])
{
if(to[i]==pre||ban[to[i]])continue;
modify(to[i],u,tag);
}
--num[c[u]];
}
void cal(int u)
{
get_sz(u,0);
tot=top=0;
dfs(u,0,cnt);
For(i,1,top)apper[col[i]]=false;
tp=top;
For(i,1,top)
{
tot+=cnt[cl[i]=col[i]];
cct[cl[i]]=cnt[cl[i]];
}
/* cout<<tot<<' '<<top<<endl;
For(i,1,n)cout<<cnt[i]<<' ';
puts("");*/
ans[u]+=tot;
ll temp=tot;
for(rg int i=head[u];i;i=nex[i])if(!ban[to[i]])
{
num[c[u]]=1,top=0;
dfs(to[i],u,ct);
num[c[u]]=0;
For(j,1,top)apper[col[j]]=false;
cnt[c[u]]-=size[to[i]];
tot-=size[to[i]];
For(j,1,top)
{
cnt[col[j]]-=ct[col[j]];
tot-=ct[col[j]];
}
path=size[u]-size[to[i]];
modify(to[i],u,0);
cnt[c[u]]+=size[to[i]];
tot=temp;
For(j,1,top)
{
cnt[col[j]]=cct[col[j]];
ct[col[j]]=0;
}
}
For(i,1,tp)cnt[cl[i]]=0;
}
void solve(int u)
{
ban[u]=true;
cal(u);
for(rg int i=head[u];i;i=nex[i])
{
if(ban[to[i]])continue;
get_sz(to[i],u);
min_sz=sum=size[to[i]];
get_root(to[i],u);
solve(root);
}
}
void work()
{
sum=min_sz=n;
get_sz(1,0);
get_root(1,0);
solve(1);
For(i,1,n)write(ans[i],'\n');
}
int main()
{
file();
input();
work();
return 0;
}

luogu P2644 树上游戏的更多相关文章

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

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

  2. [LuoGu]P2664 树上游戏

    Portal 这题真的好. 看到树上路径, 脑子里就要点分治 这一题对于每个点都要计算一遍, 如果暴算实在不好算, 这样我们就可以考虑算贡献. 直接计算每种颜色的贡献. 因为一条过重心的路径中, 可能 ...

  3. luogu P2664 树上游戏(点分治)

    点分治真是一个好东西.可惜我不会 这种要求所有路经的题很可能是点分治. 然后我就不会了.. 既然要用点分治,就想,点分治有哪些优点?它可以\(O(nlogn)\)遍历分治树的所有子树. 那么现在的问题 ...

  4. P2664 树上游戏

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

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

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

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

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

  7. LG2664 树上游戏

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

  8. [luogu]P1070 道路游戏[DP]

    [luogu]P1070 道路游戏 题目描述小新正在玩一个简单的电脑游戏.游戏中有一条环形马路,马路上有 n 个机器人工厂,两个相邻机器人工厂之间由一小段马路连接.小新以某个机器人工厂为起点,按顺时针 ...

  9. [Luogu P3825] [NOI2017] 游戏 (2-SAT)

    [Luogu P3825] [NOI2017] 游戏 (2-SAT) 题面 题面较长,略 分析 看到这些约束,应该想到这是类似2-SAT的问题.但是x地图很麻烦,因为k-SAT问题在k>2的时候 ...

随机推荐

  1. C#中用OLEDB操作EXCEL时,单元格内容长度超过255被截断

    C#中Microsoft.ACE.OLEDB.12.0 驱动读取excel,会读取前8行来判定每列的数据类型,假如没有超过255个字符,那么会被设置为nvarchar(255),从第9行开始,超过25 ...

  2. Python爬虫利器二之Beautiful Soup的用法

    上一节我们介绍了正则表达式,它的内容其实还是蛮多的,如果一个正则匹配稍有差池,那可能程序就处在永久的循环之中,而且有的小伙伴们也对写正则表达式的写法用得不熟练,没关系,我们还有一个更强大的工具,叫Be ...

  3. Zookeeper Windows版的服务安装和管理工具

    以前研究过负载均衡,最近正在项目上实施(从来没做过小项目以上级别的东西,哈).然后遇到了多个一模一样但是同时运行的服务.不同服务但依赖同相同的配置数据(前端网页服务:Nginx+IIS+nodejs. ...

  4. Wechat login authorization(OAuth2.0)

    一.前言 昨天小组开了个会,让我今天实现一个微信网页授权的功能,可以让用户在授权之后无需再次登录既可进入用户授权界面.在这之前我也从没接触过微信公众号开发之类的,也不知道公众号后台是啥样子的,自己所在 ...

  5. C/C++中int128的那点事

    最近群友对int128这个东西讨论的热火朝天的.讲道理的话,编译器的gcc是不支持__int128这种数据类型的,比如在codeblocks 16.01/Dev C++是无法编译的,但是提交到大部分O ...

  6. Spring AOP不起作用原因

    一.直接在切面类定义切点: AOP切面类里面的方法全部不支持触发切面,否则一个切面函数把自己当做切点就会导致递归层层调用. AOP切面类发出函数调用一律不触发切面,避免两个切面类相互调用迭代请求的情况 ...

  7. ZooKeeper 典型的应用场景——及编程实现

    如何使用 Zookeeper 作为一个分布式的服务框架,主要用来解决分布式集群中应用系统的一致性问题,它能提供基于类似于文件系统的目录节点树方式的数据存储,但是 Zookeeper 并不是用来专门存储 ...

  8. python基础学习笔记(十三)

    re模块包含对 正则表达式.本章会对re模块主要特征和正则表达式进行介绍. 什么是正则表达式 正则表达式是可以匹配文本片段的模式.最简单的正则表达式就是普通字符串,可以匹配其自身.换包话说,正则表达式 ...

  9. C. Oh Those Palindromes

    题意 给以一个字符串,让你重排列,使得回文子串的数目最多 分析 对于一个回文串,在其中加入一些字符并不会使回文子串的个数增加,所以对于相同的字符一起输出即可,我是直接排序 代码 #include< ...

  10. Onezero团队第三次站立会议随感

    >首先这是一个关于Android的小应用APP(记账本) >在Java基础薄弱的基础上尝试Android开发,让我感觉力不从心. >说实话本迭代周在程序设计,确实让我头疼,不知道怎么 ...