数星星

题目链接

戳这

\(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;
}
posted @ 2024-03-23 18:28  撤云  阅读(69)  评论(0编辑  收藏  举报
……