hihocoder 1193 树堆

时间限制:20000ms
单点时限:2000ms
内存限制:256MB

描述

假定我们有一棵有根树,其中每个点上有权。它被称为树堆当且仅当每个点的权值都大于等于它的所有孩子。

现在我们有一棵有根树,它的每个点上有权。我们可以不断对它进行如下的操作:选择一个非根结点v,删除v,然后将v的所有孩子连到v的父亲上。

不断进行以上操作,此时可能一个子树会形成树堆。

对树上的每个结点x,求出以这种方式形成的以x为根的树堆中,结点最多的树堆的结点个数。

输入

第一行n,树上的点数。

第二行n个用空格分开的整数a0, ..., an - 1。ai为点i的权值。

下面n - 1行,每行两个整数x, y。表示x, y间有一条边。

树的根为0。1 ≤ n ≤ 105. 0 ≤ ai ≤ 109. 0 ≤ x, y ≤ n - 1. 保证输入形成一棵树。

输出

一行,n个用空格分开的整数。第i个表示以题目中描述的方式生成的以i - 1为根的树堆中,结点最多的树堆中的结点个数。

样例输入
14
5 4 3 6 2 3 4 0 1 7 9 8 6 2
0 1
0 2
0 3
1 4
3 5
3 6
3 7
4 8
4 9
4 10
6 11
6 12
11 13
样例输出
9 3 1 5 2 1 2 1 1 1 1 2 1 1

思路: 本题是线段树合并,只要从底往上不断的合并就可以了。ans[x]表示以x为根的树最多可以的点的数量。 mx[x]表示当前区间最多可以得到的点,tg[x]是一个加的标记。
我们先求出p,即在叶子节点的位置,然后去ask查询在p这个位置最多可以得到的值。然后我们去find最早能够得到ans[x]的位置r,因为很明显的,数越大树堆的规模也就最大。
然后我们对p到r-1这个范围内都加一。
 1 #include<bits/stdc++.h>
 2 using namespace std;  
 3 #define R register int  
 4 #define rep(i,a,b) for(R i=a;i<=b;i++)  
 5 #define Rep(i,a,b) for(R i=a;i>=b;i--)  
 6 #define ms(i,a)    memset(a,i,sizeof(a)) 
 7 #define mid        (l+r)/2  
 8 #define gc()       getchar() 
 9 template<class T>void read(T &x){
10     x=0; char c=0; 
11     while (!isdigit(c)) c=gc();  
12     while (isdigit(c)) x=x*10+(c^48),c=gc();  
13 }
14 int const N=100000+3;  
15 struct Edge{
16     int to,nt; 
17 }E[N<<1];  
18 int H[N],a[N],b[N],cnt,sum,lc[N*40],rc[N*40],tg[N*40],mx[N*40],n,m,ans[N],rt[N];  
19 void addE(int a,int b){
20     E[cnt]=(Edge){b,H[a]}; H[a]=cnt++;  
21 }
22 void add(int x,int v){
23     tg[x]+=v;mx[x]+=v;  
24 }
25 void pushdown(int x){
26     if(tg[x]){
27         if(!lc[x]) lc[x]=++sum;  
28         if(!rc[x]) rc[x]=++sum;  
29         add(lc[x],tg[x]); 
30         add(rc[x],tg[x]);  
31         tg[x]=0;  
32     }
33 }
34 int ask(int x,int l,int r,int p){
35     if(!lc[x] && !rc[x]) return mx[x];  
36     pushdown(x);  
37     if(p<=mid) return ask(lc[x],l,mid,p);  
38     else return ask(rc[x],mid+1,r,p);  
39 }
40 int find(int x,int l,int r,int v){
41     if(mx[x]<v) return r+1;  
42     if(!lc[x] && !rc[x]) return l;  
43     pushdown(x);  
44     if(mx[lc[x]]>=v) return  find(lc[x],l,mid,v); 
45     else return find(rc[x],mid+1,r,v);  
46 }
47 
48 void update(int &x,int l,int r,int ll,int rr){
49     if(!x) x=++sum;  
50     if(ll<=l && r<=rr){
51         add(x,1);  return;  
52     }
53     pushdown(x);  
54     if(ll<=mid) update(lc[x],l,mid,ll,rr); 
55     if(rr>mid)  update(rc[x],mid+1,r,ll,rr);  
56     mx[x]=max(mx[lc[x]],mx[rc[x]]);  
57 }
58 int merge(int x,int y){
59     if(!x) return y;  
60     if(!y) return x;  
61     if(!lc[x] && !rc[x])  swap(x,y);  
62     if(!lc[y] && !rc[y]) add(x,mx[y]);  
63     else {
64         pushdown(x); pushdown(y);  
65         lc[x]=merge(lc[x],lc[y]);  
66         rc[x]=merge(rc[x],rc[y]);  
67         mx[x]=max(mx[lc[x]],mx[rc[x]]);  
68     }
69     return x;  
70 }
71 
72 void dfs(int x,int fa){
73     for(R i=H[x];i!=-1;i=E[i].nt){
74         int v=E[i].to;  
75         if(v==fa) continue;  
76         dfs(v,x);  
77         rt[x]=merge(rt[x],rt[v]);  
78     }
79     int p=lower_bound(b+1,b+n+1,a[x])-b;  
80     ans[x]=ask(rt[x],1,n,p)+1; 
81     int r=find(rt[x],1,n,ans[x]);   
82     update(rt[x],1,n,p,r-1);   
83 }
84 int main(){
85     read(n);  
86     ms(-1,H);  
87     rep(i,1,n) read(a[i]),b[i]=a[i];  
88     sort(b+1,b+n+1); 
89     rep(i,1,n-1){
90         int x,y;
91         read(x); read(y);
92         x++; y++;    
93         addE(x,y);addE(y,x); 
94     }
95     dfs(1,0);  
96     rep(i,1,n) printf("%d ",ans[i]); 
97     return 0; 
98 }
View Code

 

posted @ 2019-03-14 16:27  zjxxcn  阅读(153)  评论(0编辑  收藏  举报