J 买一送一 主席树

J买一送一
题意:给你一个树,每个节点都有权值,求由根节点到每个叶子节点能够有效的有序(x,y)的对数,有先后顺序。
题解:很容易出思路,我在树上建主席树,直接上代码。
注意:就是去重不是那么容易,你对一条链上的每个点,如果一个数出现两和出现两次以上是不一样的,还有就是同一个数,对于两条树链是不一样的。

#include<bits/stdc++.h>
#define ll long long
#define m (l+r)/2
using namespace std;
const int maxn = 1e5+10;
int tr[maxn*20] ,ls[maxn*20] ,rs[maxn*20] ,rt[maxn] ,cnt,n,a[maxn],id[maxn],c[maxn];
ll ans[maxn];
vector<int>G[maxn];
void up(int &o,int pre,int l,int r,int k)
{
    o = ++cnt;
    ls[o] = ls[pre] ;
    rs[o] = rs[pre] ;
    tr[o] = tr[pre] + 1;
    if(l==r) return ;
    if(k>m) up(rs[o],rs[pre],m+1,r,k);
    else up(ls[o],ls[pre],l,m,k);
    tr[o] = tr[ls[o]] + tr[rs[o]];
}
void dfs(int u,int fa)
{
    ans[u] = ans[fa];
    rt[u] = rt[fa];
    int tmp = id[a[u]],tp = c[a[u]];
    if(id[a[u]]==0){
      up(rt[u],rt[fa],1,n,a[u]);
      ans[u] += tr[rt[u]] - 1;
      id[a[u]] = u;
      c[a[u]] ++ ;
    }
    else {
    if(c[a[u]]==1)
     ans[u] += tr[rt[u]] - tr[rt[id[a[u]]]] + 1 ;
    else ans[u] += tr[rt[u]] - tr[rt[id[a[u]]]];
     c[a[u]] ++ ;
     id[a[u]] = u;
    }
    for(auto v:G[u])
    if(v!=fa) dfs(v,u);
    id[a[u]] = tmp;
    c[a[u]] = tp;
}
int main()
{
    int v;
    while(~scanf("%d",&n))
    {
        cnt = 0;
    for(int i=0;i<=n*4;i++)tr[i] = ls[i] = rs[i] = 0;
    for(int i=0;i<=n;i++) G[i].clear(),ans[i] = id[i] = c[i] = 0;
     for(int i=2;i<=n;i++){
            scanf("%d",&v);
            G[v].push_back(i);
            G[i].push_back(v);
    }
     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
     dfs(1,0);
    for(int i=2;i<=n;i++)printf("%lld\n",ans[i]);
    }
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值