【USACO17JAN】Promotion Counting P

题目链接

如果只有一条链,可以直接离散化上权值树状数组一遍过。

在树上,考虑怎么消除不同子树之间的影响。

略微思考可以得出,可以在递归子树之前先求一遍询问前缀存下来,回溯回来再求一遍询问前缀,减一下得到子树新增的前缀。再用子树大小减一下,就是当前子树的答案。

 

代码(100分):

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<set>
#define IL inline
#define RG register
#define _1 first
#define _2 second
using namespace std;
const int N=1e5;

    int n,p[N+3];
    
struct Edge{
    int to,nxt;
}e[N+3];
    int top,h[N+3];

IL void gra_init(){
    top=-1;
    memset(h,-1,sizeof h);
}

IL void link(int u,int v){
    top++;;
    e[top].to=v;
    e[top].nxt=h[u];
    h[u]=top;
}

    int k,a[N+3];

IL int sol(int x){
    int l=1,r=k,mid,ans;
    while(l<=r){
        mid=(l+r)>>1;
        if(x<=a[mid]){
            r=mid-1;    ans=mid;
        }
        else 
            l=mid+1;
        
    }
    return ans;
    
}

IL void discrete(){
    memcpy(a,p,sizeof p);
    sort(a+1,a+n+1);
    k=1;
    for(int i=2;i<=n;i++)
    if(a[i]!=a[i-1])
        a[++k]=a[i];
    for(int i=1;i<=n;i++)
        p[i]=sol(p[i]);
    
}

    int s[N+3];

IL int lowbit(int x){
    return x&(-x);
}

IL void mdf(int p,int x){
    for(;p<=k;p+=lowbit(p))
        s[p]+=x;
}

IL int qry(int p){
    int ret=0;
    for(;p;p-=lowbit(p))
        ret+=s[p];
    return ret;
}

    int ans[N+3];

int dfs(int u){
    int tmp=qry(p[u]),cnt=0;
    for(int i=h[u];~i;i=e[i].nxt)
        cnt+=dfs(e[i].to);
        
    cnt++;
    mdf(p[u],1);
    ans[u]=cnt-qry(p[u])+tmp;
    return cnt;
    
}

int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&p[i]);
    gra_init();
    for(int i=2;i<=n;i++){
        int x;    scanf("%d",&x);
        link(x,i);
        
    }
    
    discrete();
    memset(s,0,sizeof s);
    dfs(1);
    for(int i=1;i<=n;i++)
        printf("%d\n",ans[i]);

    return 0;

}
View Code

 

posted @ 2020-05-22 14:11  汉谡  阅读(110)  评论(0编辑  收藏  举报