[USACO17JAN]Promotion Counting晋升者计数
Posted Z-Y-Y-S
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[USACO17JAN]Promotion Counting晋升者计数相关的知识,希望对你有一定的参考价值。
题目描述
奶牛们又一次试图创建一家创业公司,还是没有从过去的经验中吸取教训--牛是可怕的管理者!
为了方便,把奶牛从 1 \cdots N(1 \leq N \leq 100, 000)1?N(1≤N≤100,000) 编号,把公司组织成一棵树,1 号奶牛作为总裁(这棵树的根节点)。除了总裁以外的每头奶牛都有一个单独的上司(它在树上的 “双亲结点”)。所有的第 ii 头牛都有一个不同的能力指数 p(i)p(i),描述了她对其工作的擅长程度。如果奶牛 ii 是奶牛 jj 的祖先节点(例如,上司的上司的上司),那么我们我们把奶牛 jj 叫做 ii 的下属。
不幸地是,奶牛们发现经常发生一个上司比她的一些下属能力低的情况,在这种情况下,上司应当考虑晋升她的一些下属。你的任务是帮助奶牛弄清楚这是什么时候发生的。简而言之,对于公司的中的每一头奶牛 ii,请计算其下属 jj 的数量满足 p(j) > p(i)p(j)>p(i)。
输入输出格式
输入格式:
输入的第一行包括一个整数 NN。
接下来的 NN 行包括奶牛们的能力指数 p(1) \cdots p(N)p(1)?p(N). 保证所有数互不相同,在区间 1 \cdots 10^91?10?9?? 之间。
接下来的 N-1N?1 行描述了奶牛 2 \cdots N2?N 的上司(双亲节点)的编号。再次提醒,1 号奶牛作为总裁,没有上司。
输出格式:
输出包括 NN 行。输出的第 ii 行应当给出有多少奶牛 ii 的下属比奶牛 ii 能力高。
输入输出样例
5 804289384 846930887 681692778 714636916 957747794 1 1 2 3
2 0 1 0 0
树上的树状数组或线段树
维护按后序遍历树时比当前点值大的数量
但是遍历到一个点时,维护的数量可能包含了他的兄弟,祖先
所以求出每个点的答案之前,记录出值pre,在遍历子树,加入树状数组,再求出值ans[x]
ans[x]=ans[x]-pre
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 struct Messi 7 { 8 int next,to; 9 } edge[200001]; 10 int c[400001]; 11 int n,num,head[100001],a[100001],id[100001],ans[100001],p[100001]; 12 void add(int u,int v) 13 { 14 num++; 15 edge[num].next=head[u]; 16 head[u]=num; 17 edge[num].to=v; 18 } 19 int binary(int x) 20 { 21 int l=1,r=n,mid; 22 while(l<=r) 23 { 24 mid=(l+r)>>1; 25 if(a[mid]==x)return mid; 26 if(a[mid]>x)r=mid-1; 27 else l=mid+1; 28 } 29 return -1; 30 } 31 int getsum(int rt,int l,int r,int L,int R) 32 { 33 if (l>=L&&r<=R) 34 { 35 return c[rt]; 36 } 37 int mid=(l+r)/2; 38 int x=0; 39 if (L<=mid) 40 x+=getsum(rt*2,l,mid,L,R); 41 if (R>mid) 42 x+=getsum(rt*2+1,mid+1,r,L,R); 43 return x; 44 } 45 void update(int rt,int l,int r,int k) 46 { 47 if (l==r) 48 { 49 c[rt]=1; 50 return; 51 } 52 int mid=(l+r)/2; 53 if (k<=mid) 54 update(rt*2,l,mid,k); 55 else update(rt*2+1,mid+1,r,k); 56 c[rt]=c[rt*2]+c[rt*2+1]; 57 } 58 void dfs(int x) 59 {int i; 60 int tmp=getsum(1,1,n,id[x]+1,n); 61 for (i=head[x];i;i=edge[i].next) 62 { 63 dfs(edge[i].to); 64 } 65 ans[x]=getsum(1,1,n,id[x]+1,n)-tmp; 66 update(1,1,n,id[x]); 67 } 68 int main() 69 {int i,x; 70 cin>>n; 71 for (i=1; i<=n; i++) 72 { 73 scanf("%d",&p[i]); 74 a[i]=p[i]; 75 } 76 sort(a+1,a+n+1); 77 for (i=1; i<=n; i++) 78 id[i]=binary(p[i]); 79 for (i=2; i<=n; i++) 80 { 81 scanf("%d",&x); 82 add(x,i); 83 } 84 dfs(1); 85 for (i=1;i<=n;i++) 86 printf("%d\n",ans[i]); 87 }
以上是关于[USACO17JAN]Promotion Counting晋升者计数的主要内容,如果未能解决你的问题,请参考以下文章
题解晋升者计数 Promotion Counting [USACO 17 JAN] [P3605]
[USACO17JAN]Promotion Counting晋升者计数
P3605 [USACO17JAN]Promotion Counting P (dsu+线段树)
[USACO17JAN] Promotion Counting晋升者计数 (树状数组+dfs)