数星星
题目链接
\(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;
}