數星星

撤云發表於2024-03-23

題目連結

戳這

\(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;
}

相關文章