P3605 [USACO17JAN]Promotion Counting P (线段树合并)
Posted hooying
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P3605 [USACO17JAN]Promotion Counting P (线段树合并)相关的知识,希望对你有一定的参考价值。
前言
线段树合并:https://www.luogu.com.cn/blog/styx-ferryman/xian-duan-shu-ge-bing-zong-ru-men-dao-fang-qi
题意
给你一颗(n)个节点的树,每个节点都有权值且唯一,输出(n)行,输出的第(i)行应当给出有多少节点(i)的孩子比节点(i)权值大。
思路
有很多做法,这里用线段树合并来解决。
#include<bits/stdc++.h>
using namespace std;
const int maxx = 1e5+10;
int a[maxx],b[maxx];
int t[30*maxx],ls[30*maxx],rs[30*maxx],rt[maxx],cnt;
int ans[maxx];
int head[maxx],to[maxx],ne[maxx],tot;
int mx;
void add(int u,int v)
{
to[++tot]=v;ne[tot]=head[u];head[u]=tot;
}
void update(int &u,int l,int r,int x)
{
if(!u)u=++cnt;
if(l==r)
{
t[u]++;
return;
}
int mid=(l+r)/2;
if(x<=mid)update(ls[u],l,mid,x);
else update(rs[u],mid+1,r,x);
t[u]=t[ls[u]]+t[rs[u]];
}
int query(int u,int l,int r,int p,int q)
{
if(!u)return 0;
if(p<=l&&r<=q)return t[u];
int mid=(l+r)/2;
int ans=0;
if(p<=mid)ans+=query(ls[u],l,mid,p,q);
if(q>mid)ans+=query(rs[u],mid+1,r,p,q);
return ans;
}
int merge(int a,int b,int l,int r)
{
if(!a)return b;
if(!b)return a;
if(l==r)
{
t[a]+=t[b];
return a;
}
int mid=(l+r)/2;
ls[a]=merge(ls[a],ls[b],l,mid);
rs[a]=merge(rs[a],rs[b],mid+1,r);
t[a]=t[ls[a]]+t[rs[a]];
return a;
}
void dfs(int u)
{
for(int i=head[u];i;i=ne[i])
{
dfs(to[i]);
rt[u]=merge(rt[u],rt[to[i]],1,mx);
}
ans[u]=query(rt[u],1,mx,min(a[u]+1,mx),mx);
update(rt[u],1,mx,a[u]);
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),b[i]=a[i];
int x;
for(int i=2;i<=n;i++)
scanf("%d",&x),add(x,i);
sort(b+1,b+1+n);
mx=unique(b+1,b+1+n)-b-1;
for(int i=1;i<=n;i++)
a[i]=lower_bound(b+1,b+1+mx,a[i])-b;
dfs(1);
for(int i=1;i<=n;i++)
printf("%d
",ans[i]);
return 0;
}
以上是关于P3605 [USACO17JAN]Promotion Counting P (线段树合并)的主要内容,如果未能解决你的问题,请参考以下文章
P3605 [USACO17JAN]Promotion Counting P (dsu+线段树)
P3605 [USACO17JAN]Promotion Counting P (线段树合并)
P3605 [USACO17JAN]Promotion Counting P (线段树合并)
P3605 [USACO17JAN]Promotion Counting P(树状数组)