SPOJ-BDOI16E Village Fair(dsu+离散化)

题意

给定一棵 n 个节点的树,树的每一个节点有一个欢乐值,每个节点有一个小朋友,每个小朋友有一个初始快乐值。现在每个小朋友将往根跑,并加上经过点的快乐值。求到每个节点上出现不同快乐值的小朋友总数。
1 n 100000

思路

对于一个节点 u ,走过这个节点后的小朋友们加的值都一样了,所以,询问 u 子树节点中走到 u 不同的快乐值总数,相当于询问 u 子树中走到根不同的快乐值数。所以只用于处理出每个节点上的小朋友走到根的总快乐值,然后查询就相当于在子树中找不同数值的个数。由此想到 d s u ,但这个快乐值又太大,用 s e t 会浪费时间,离散后用一个普通数组即可。

代码

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define FOR(i,x,y) for(int i=(x);i<=(y);i++)
#define DOR(i,x,y) for(int i=(x);i>=(y);i--)
#define N 100003
typedef long long LL;
using namespace std;
template<const int maxn,const int maxm>struct Linked_list
{
    int head[maxn],to[maxm],nxt[maxm],tot;
    void clear(){memset(head,-1,sizeof(head));tot=0;}
    void add(int u,int v){to[++tot]=v,nxt[tot]=head[u];head[u]=tot;}
    #define EOR(i,G,u) for(int i=G.head[u];~i;i=G.nxt[i])
};
Linked_list<N,N<<1>G;
int sz[N],son[N],L[N],R[N],ori[N],Out[N],extra[N],cnt[N];
LL a[N],b[N];
int n,ord,ans;

void dfs(int u,int f,LL sum)
{
    L[u]=++ord,ori[ord]=u;
    sz[u]=1,son[u]=0,sum+=extra[u];
    a[u]+=sum;
    EOR(i,G,u)
    {
        int v=G.to[i];
        if(v==f)continue;
        dfs(v,u,sum);
        sz[u]+=sz[v];
        if(sz[v]>sz[son[u]])son[u]=v;
    }
    R[u]=ord;
}
void update(int L,int R,int val)
{
    FOR(i,L,R)
    {
        int up=a[ori[i]];
        if(cnt[up])ans--;
        cnt[up]+=val;
        if(cnt[up])ans++;
    }
}
void dsu(int u,int f)
{
    EOR(i,G,u)
    {
        int v=G.to[i];
        if(v==f||v==son[u])continue;
        dsu(v,u);update(L[v],R[v],-1);
    }
    if(son[u])dsu(son[u],u);
    EOR(i,G,u)
    {
        int v=G.to[i];
        if(v==f||v==son[u])continue;
        update(L[v],R[v],1);
    }
    update(L[u],L[u],1);
    Out[u]=ans;
}

int main()
{
    G.clear();
    memset(cnt,0,sizeof(cnt));
    ord=ans=0;
    scanf("%d",&n);
    FOR(i,1,n)scanf("%lld",&a[i]);
    int rot;
    FOR(i,1,n)
    {
        int u;
        scanf("%d",&u);
        if(u)G.add(u,i);
        else rot=i;
    }
    FOR(i,1,n)scanf("%d",&extra[i]);
    dfs(rot,0,0);
    FOR(i,1,n)b[i]=a[i];
    sort(b+1,b+1+n);
    FOR(i,1,n)a[i]=lower_bound(b+1,b+1+n,a[i])-b;
    dsu(rot,0);
    FOR(i,1,n)printf("%d\n",Out[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Paulliant/article/details/81428791