J买一送一
题意:给你一个树,每个节点都有权值,求由根节点到每个叶子节点能够有效的有序(x,y)的对数,有先后顺序。
题解:很容易出思路,我在树上建主席树,直接上代码。
注意:就是去重不是那么容易,你对一条链上的每个点,如果一个数出现两和出现两次以上是不一样的,还有就是同一个数,对于两条树链是不一样的。
#include<bits/stdc++.h>
#define ll long long
#define m (l+r)/2
using namespace std;
const int maxn = 1e5+10;
int tr[maxn*20] ,ls[maxn*20] ,rs[maxn*20] ,rt[maxn] ,cnt,n,a[maxn],id[maxn],c[maxn];
ll ans[maxn];
vector<int>G[maxn];
void up(int &o,int pre,int l,int r,int k)
{
o = ++cnt;
ls[o] = ls[pre] ;
rs[o] = rs[pre] ;
tr[o] = tr[pre] + 1;
if(l==r) return ;
if(k>m) up(rs[o],rs[pre],m+1,r,k);
else up(ls[o],ls[pre],l,m,k);
tr[o] = tr[ls[o]] + tr[rs[o]];
}
void dfs(int u,int fa)
{
ans[u] = ans[fa];
rt[u] = rt[fa];
int tmp = id[a[u]],tp = c[a[u]];
if(id[a[u]]==0){
up(rt[u],rt[fa],1,n,a[u]);
ans[u] += tr[rt[u]] - 1;
id[a[u]] = u;
c[a[u]] ++ ;
}
else {
if(c[a[u]]==1)
ans[u] += tr[rt[u]] - tr[rt[id[a[u]]]] + 1 ;
else ans[u] += tr[rt[u]] - tr[rt[id[a[u]]]];
c[a[u]] ++ ;
id[a[u]] = u;
}
for(auto v:G[u])
if(v!=fa) dfs(v,u);
id[a[u]] = tmp;
c[a[u]] = tp;
}
int main()
{
int v;
while(~scanf("%d",&n))
{
cnt = 0;
for(int i=0;i<=n*4;i++)tr[i] = ls[i] = rs[i] = 0;
for(int i=0;i<=n;i++) G[i].clear(),ans[i] = id[i] = c[i] = 0;
for(int i=2;i<=n;i++){
scanf("%d",&v);
G[v].push_back(i);
G[i].push_back(v);
}
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
dfs(1,0);
for(int i=2;i<=n;i++)printf("%lld\n",ans[i]);
}
}