给出一个根为
1
1
1,
n
≤
1
e
5
n\leq1e5
n≤1e5有点权的树,定义每个结点
f
(
i
)
f(i)
f(i)为从根结点到这个结点上任选两个点
u
,
v
u,v
u,v的点权构成的不同的
<
w
(
u
)
,
w
(
v
)
>
<w(u),w(v)>
<w(u),w(v)>的个数。求
∀
i
∈
[
2
,
n
]
\forall i\in [2,n]
∀i∈[2,n]的
f
(
i
)
f(i)
f(i)。
遍历树时候如果
v
v
v是
u
u
u的儿子,分为两种情形:选择
v
v
v这个点和不选择
v
v
v这个点,如果不选择
v
v
v这个点答案为
f
(
u
)
f(u)
f(u);如果选择这个点,答案为路径上所有不同数的个数减去当前点权上次出现的时候不同数的个数。
对所有的权值开一个栈记录一下。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
static const int maxn = 100010;
static const int INF = 0x3f3f3f3f;
static const int mod = (int)1e9 + 7;
static const double eps = 1e-6;
static const double pi = acos(-1);
const int N=1e5+7;
int app[N];
int w[N];
ll f[N];
vector<int> go[N];
vector<int> s[N];
void clear(int n) {
for(int i=1;i<=n;i++) {
s[i].clear();
go[i].clear();
}
memset(app,0,sizeof(app));
memset(f,0,sizeof(f));
}
int sum=0;
void dfs(int u,int fa) {
s[w[u]].push_back(sum);
if(app[w[u]]==0) sum++;
app[w[u]]++;
for(auto &v:go[u]) {
if(v==fa) continue;
f[v]=f[u]+sum;
if(!s[w[v]].empty())
f[v]-=s[w[v]].back();
dfs(v,u);
}
app[w[u]]--;
if(app[w[u]]==0) sum--;
s[w[u]].pop_back();
}
int main(){
int n;
while(scanf("%d",&n)!=EOF) {
clear(n);
for(int i=2;i<=n;i++) {
int u;
scanf("%d",&u);
go[u].push_back(i);
go[i].push_back(u);
}
for(int i=1;i<=n;i++)
scanf("%d",&w[i]);
dfs(1,0);
for(int i=2;i<=n;i++)
printf("%lld\n",f[i]);
}
return 0;
}