P3605 [USACO17JAN]Promotion Counting晋升者计数

题面

一道线段树合并的入门题

直接建一堆权值线段树然后合并就可以了

下面是代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cctype>
#define ll long long
#define gc getchar
#define maxn 100005
using namespace std;

inline ll read(){
    ll a=0;int f=0;char p=gc();
    while(!isdigit(p)){f|=p=='-';p=gc();}
    while(isdigit(p)){a=(a<<3)+(a<<1)+(p^48);p=gc();}
    return f?-a:a;
}int n,cnt,a[maxn],b[maxn],ans[maxn];

struct ahaha{
    int v,ch[2];
}t[maxn*20];int top,rt[maxn];
#define lc t[i].ch[0]
#define rc t[i].ch[1]
void update(int &i,int l,int r,int k){
    if(!i)i=++top;++t[i].v;
    if(l==r)return;
    int m=l+r>>1;
    if(k<=m)update(lc,l,m,k);
    else update(rc,m+1,r,k);
}
int query(int i,int l,int r,int L,int R){
    if(!i)return 0;
    if(l>R||r<L)return 0;
    if(L<=l&&r<=R)return t[i].v;
    int m=l+r>>1;
    return query(lc,l,m,L,R)+query(rc,m+1,r,L,R);
}
int merge(int x,int y){
    if(!x||!y)return x+y;
    int i=++top;t[i].v=t[x].v+t[y].v;
    lc=merge(t[x].ch[0],t[y].ch[0]);
    rc=merge(t[x].ch[1],t[y].ch[1]);
    return i;
}

struct ahaha1{
    int to,next;
}e[maxn];int tot,head[maxn];
inline void add(int u,int v){
    e[tot]={v,head[u]};head[u]=tot++;
}
void dfs(int u){
    for(int i=head[u];~i;i=e[i].next){
        int v=e[i].to;dfs(v);
        rt[u]=merge(rt[u],rt[v]);
    }
    ans[u]=query(rt[u],1,cnt,a[u]+1,cnt);
    update(rt[u],1,cnt,a[u]);
}

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

转载于:https://www.cnblogs.com/hanruyun/p/10429182.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值