[BZOJ4756][Usaco2017 Jan]Promotion Counting:树状数组/线段树合并

解法一分析:

离散化后遍历一遍整棵树,发现子树信息为离开子树时的信息减去进入子树时的信息。
树状数组维护权值即可。

解法一代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#define lowbit(x) ((x)&(-(x)))

inline int read(){
    int x=0;char ch=getchar();
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x;
}

const int MAXN=100005;
int n,a[MAXN],b[MAXN],siz,ecnt,head[MAXN],ans[MAXN];
struct Edge{
    int to,nxt;
}e[MAXN];

inline void add_edge(int bg,int ed){
    ecnt++;
    e[ecnt].to=ed;
    e[ecnt].nxt=head[bg];
    head[bg]=ecnt;
}

inline void Add(int x){
    for(int i=x;i<=siz;i+=lowbit(i))
        b[i]++;
}

inline int Ask(int x){
    int ret=0;
    for(int i=x;i;i-=lowbit(i))
        ret+=b[i];
    return ret;
}

void dfs(int x){
    ans[x]-=Ask(siz)-Ask(a[x]);
    Add(a[x]);
    for(int i=head[x];i;i=e[i].nxt) dfs(e[i].to);
    ans[x]+=Ask(siz)-Ask(a[x]);
}

int main(){
    n=read();
    for(int i=1;i<=n;i++) b[i]=a[i]=read();
    std::sort(b+1,b+n+1);
    siz=std::unique(b+1,b+n+1)-b-1;
    for(int i=1;i<=n;i++) a[i]=std::lower_bound(b+1,b+siz+1,a[i])-b;
    memset(b,0,sizeof b);
    for(int i=2;i<=n;i++) add_edge(read(),i);
    dfs(1);
    for(int i=1;i<=n;i++) printf("%d\n",ans[i]);
    return 0;
}

解法二分析:

解法二代码:

猜你喜欢

转载自www.cnblogs.com/ErkkiErkko/p/9720514.html