iai 彩色树 题解

前置题目:树的颜色(时序差分)。

每种颜色的贡献为至少出现一次的路径数。容斥,总路径数减去未出现过的路径数。

考虑颜色 c c c 的贡献,此时将所有颜色为 c c c 的点移去,会形成若干连通块。对于大小为 x x x 的连通块,其贡献为 x ( x − 1 ) 2 \frac{x(x-1)}{2} 2x(x1)

在这里插入图片描述

在这些颜色为 c c c 的点(以及根节点)处计算对应块的贡献即可。

f c ( u ) f_c(u) fc(u) 表示以 u u u 为根子树内,无颜色 c c c 的极大连通块大小。

颜色 c c c 贡献:

∑ u , c o l u = c ∑ v ∈ s o n u f c ( v ) ( f c ( v ) − 1 ) 2 + f c ( 1 ) ( f c ( 1 ) − 1 ) 2 \sum_{u,col_u=c} \sum _ {v\in son_u} \frac{f_c(v)(f_c(v)-1)}{2}+\frac{f_c(1)(f_c(1)-1)}{2} u,colu=cvsonu2fc(v)(fc(v)1)+2fc(1)(fc(1)1)

f f f 显然可以通过时序差分降维。

实现可能会有个简单的标记永久化思想,或者通过状态转成补集避免标记。

#include<bits/stdc++.h>
#define int long long
using namespace std;

const int N = 2e5 + 5;

int n, col[N], p[N], ans, f[N], tag;

vector <int> son[N];

int s(int x){return x*(x-1)/2;}

void dfs(int u)
{
	f[col[u]] --, tag ++ ;
	for(auto v : son[u])
	{
		int before = f[col[u]] + tag;
		dfs(v);
		int after = f[col[u]] + tag;
		int cur = after - before;
		ans -= s(cur); f[col[u]] -= cur;
	}
}

signed main()
{
	ios::sync_with_stdio(0); cin.tie(0);
	
	cin >> n;
	
	for(int i=1; i<=n; i++) cin >> col[i];
	
	for(int i=2; i<=n; i++) cin >> p[i], son[p[i]].push_back(i);
	
	ans = n * s(n);
	
	dfs(1);
	
	for(int i=1; i<=n; i++) 
		ans -= s(f[i] + tag);
		
	cout << ans;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值