題目連結
戳這
\(Solution\)
對於一個樹他的子樹的\(dfs\)序一定是連續的,所以可以把這個樹化成鏈,問題就轉化為了對於一段區間中星星的種類是否都不同,然後這個東西可以繼續變成區間的不同種類個數是否等於區間長度,區間不同種類個數就很好求了可以看看HH的項鍊 如果這題範圍是\(1e5\)的話可以用莫隊暴力搞過去,但是是\(2e6\)所以就只能用\(log\)的做法。
將區間按右端點排序然後遍歷一下看這個位置是否出現過,如果出現過則把上個位置的值\(-1\)。遍歷到一個點將這個點的值標記一下表示最後出現的位置。然後將這個點的值\(+1\).對於答案就是區間的和。這個東西用樹狀陣列或者線段樹搞一下就行。
\(code\)
```#include<bits/stdc++.h>
using namespace std;
int read() {
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9') f=(c=='-')?-1:1,c=getchar();
while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*f;
}
int val[2000011];
struct tree {
int next,to;
}a[4000011];
struct node{
int l,r,id;
}c[2000011];
int cnt,head[2000011],siz[2000011],dfn[2000011],b[2000011],js;
void add(int x,int y){
a[++cnt].next=head[x];
a[cnt].to=y;
head[x]=cnt;
}
void dfs(int x){
siz[x]=1;
dfn[x]=++js;
b[js]=val[x];
for(int i=head[x];i;i=a[i].next){
int v=a[i].to;
dfs(v);
siz[x]+=siz[v];
}
}
int d[2000011],n,x;
bool cmp(const node & a , const node & b ){
return a.r<b.r;
}
int lowbit(int x){
return x&(-x);
}
void Add(int x,int c){
while(x<=n) d[x]+=c,x+=lowbit(x);
}
int sum(int x){
int ans=0;
while(x) ans+=d[x],x-=lowbit(x);
return ans;
}
int bj[2000011];
int main(){
n=read(),x;
for(int i=1;i<=n;i++) val[i]=read();
for(int i=1;i<n;i++) x=read(),add(x,i+1);
dfs(1);
for(int i=1;i<=n;i++){
c[i].l=dfn[i],c[i].r=dfn[i]+siz[i]-1,c[i].id=i;
}
sort(c+1,c+1+n,cmp);
int now=1,ans=0;
for(int i=1;i<=n;i++){
for(int j=now;j<=c[i].r;j++){
if(bj[b[j]]) Add(bj[b[j]],-1);
Add(j,1);
bj[b[j]]=j;
}
now=c[i].r+1;
if(sum(c[i].r)-sum(c[i].l-1)==siz[c[i].id]) ans++;
}
cout<<ans;
}