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 }