BZOJ4756:[USACO]Promotion Counting(线段树合并)
Description
n只奶牛构成了一个树形的公司,每个奶牛有一个能力值pi,1号奶牛为树根。
问对于每个奶牛来说,它的子树中有几个能力值比它大的。
问对于每个奶牛来说,它的子树中有几个能力值比它大的。
Input
n,表示有几只奶牛 n<=100000
接下来n行为1-n号奶牛的能力值pi
接下来n-1行为2-n号奶牛的经理(树中的父亲)
接下来n行为1-n号奶牛的能力值pi
接下来n-1行为2-n号奶牛的经理(树中的父亲)
Output
共n行,每行输出奶牛i的下属中有几个能力值比i大
Sample Input
5
804289384
846930887
681692778
714636916
957747794
1
1
2
3
804289384
846930887
681692778
714636916
957747794
1
1
2
3
Sample Output
2
0
1
0
0
0
1
0
0
Solution
线段树合并模板题,$DFS$一遍,然后把儿子的线段树合并到自己身上,查询比自己能力值大的有多少个。
Code
1 #include<iostream> 2 #include<cstdio> 3 #define N (100009) 4 #define INF (1000000000) 5 using namespace std; 6 7 struct Sgt{int ls,rs,val;}Segt[N<<5]; 8 struct Edge{int to,next;}edge[N<<1]; 9 int n,x,sgt_num,a[N],ans[N],Root[N]; 10 int head[N],num_edge; 11 12 void add(int u,int v) 13 { 14 edge[++num_edge].to=v; 15 edge[num_edge].next=head[u]; 16 head[u]=num_edge; 17 } 18 19 void Update(int &now,int l,int r,int x) 20 { 21 if (!now) now=++sgt_num; 22 Segt[now].val++; 23 if (l==r) return; 24 int mid=(l+r)>>1; 25 if (x<=mid) Update(Segt[now].ls,l,mid,x); 26 else Update(Segt[now].rs,mid+1,r,x); 27 } 28 29 int Query(int now,int l,int r,int l1,int r1) 30 { 31 if (l>r1 || r<l1) return 0; 32 if (l1<=l && r<=r1) return Segt[now].val; 33 int mid=(l+r)>>1,ls=Segt[now].ls,rs=Segt[now].rs; 34 return Query(ls,l,mid,l1,r1)+Query(rs,mid+1,r,l1,r1); 35 } 36 37 void Merge(int &x,int y) 38 { 39 if (!x || !y) {x|=y; return;} 40 Segt[x].val+=Segt[y].val; 41 Merge(Segt[x].ls,Segt[y].ls); 42 Merge(Segt[x].rs,Segt[y].rs); 43 } 44 45 void DFS(int x,int fa) 46 { 47 for (int i=head[x]; i; i=edge[i].next) 48 if (edge[i].to!=fa) 49 { 50 DFS(edge[i].to,x); 51 Merge(Root[x],Root[edge[i].to]); 52 } 53 ans[x]=Query(Root[x],1,INF,a[x]+1,INF); 54 } 55 56 int main() 57 { 58 scanf("%d",&n); 59 for (int i=1; i<=n; ++i) 60 { 61 scanf("%d",&a[i]); 62 Update(Root[i],1,INF,a[i]); 63 } 64 for (int i=2; i<=n; ++i) 65 { 66 scanf("%d",&x); 67 add(i,x); add(x,i); 68 } 69 DFS(1,0); 70 for (int i=1; i<=n; ++i) 71 printf("%d\n",ans[i]); 72 }