[USACO17JAN]Promotion Counting P 主席树

洛谷P3605

首先$dfs$一遍,记录每个节点的$dfs$序和其子树大小。

$p[i]$经离散化处理后按照$dfs$序的顺序建立主席树,每个节点的求解即为其子树内$p$值小于该节点的节点数。

主席数差分查询即可。

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int n,m,x,a[maxn],b[maxn],T[maxn];
int sum[maxn<<5],L[maxn<<5],R[maxn<<5];
int cnt,head[maxn],siz[maxn],pos[maxn],rk[maxn],tot;
struct Edge{
    int to,next;
}e[maxn];
void add(int u,int v) {
    e[++cnt].to=v;
    e[cnt].next=head[u];
    head[u]=cnt;
}
void dfs(int u) {
    siz[u]=1;
    pos[u]=++tot;
    rk[tot]=u;
    for(int i=head[u];i;i=e[i].next) {
        int v=e[i].to;
        dfs(v);
        siz[u]+=siz[v];
    }
}
int build(int l,int r) {
    int rt=++tot;
    if(l<r) {
        int mid=l+r>>1;
        L[rt]=build(l,mid),R[rt]=build(mid+1,r);
    }
    return rt;
}
int update(int pre,int l,int r,int pos) {
    int rt=++tot;
    L[rt]=L[pre],R[rt]=R[pre],sum[rt]=sum[pre]+1;
    if(l<r) {
        int mid=l+r>>1;
        if(pos<=mid) L[rt]=update(L[pre],l,mid,pos);
        else R[rt]=update(R[pre],mid+1,r,pos);
    }
    return rt;
}
int query(int u,int v,int l,int r,int L_,int R_) {
    if(L_<=l&&R_>=r) return sum[v]-sum[u];
    int mid=l+r>>1,res=0;
    if(L_<=mid) res+=query(L[u],L[v],l,mid,L_,R_);
    if(R_>mid) res+=query(R[u],R[v],mid+1,r,L_,R_);
    return res;
}
int main() {
    scanf("%d",&n);
    for(int i=1;i<=n;++i) scanf("%d",&a[i]),b[i]=a[i];
    sort(b+1,b+1+n),m=unique(b+1,b+1+n)-b-1;
    for(int i=1;i<=n;++i) a[i]=lower_bound(b+1,b+1+n,a[i])-b;
    for(int i=2;i<=n;++i) scanf("%d",&x),add(x,i);
    dfs(1);
    tot=0;
    T[0]=build(1,m);
    for(int i=1;i<=n;++i) T[i]=update(T[i-1],1,m,a[rk[i]]);
    for(int i=1;i<=n;++i) printf("%d\n",query(T[pos[i]],T[pos[i]+siz[i]-1],1,m,a[i]+1,m));
    return 0;
}
posted @ 2020-11-25 21:44  Kaiser_Kell  阅读(101)  评论(1编辑  收藏  举报