题目链接:点击打开链接
题目大意:给出一棵树,n个点,每个点都有一个权值,现在定义一个集合,集合中的点按照权值排序,v[i]到v[i+1]的路径上的点都比v[i]的权值小,问集合中最多能有多少个点。
如果存在一个集合满足这些条件,那么肯定有一个中心点,这个中心点按照它能到达的路径上的点权值不断在增加,这样中点最小,其他的分支上的点越远离中点越大。dp1[i]记录以i为根的子树上向下,从w[i]开始不断增加权值的路径上点的个数。dp2[i]是从i向上搜索,权值不断增加的点的个数。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
#pragma comment(linker,"/STACK:102400000,102400000")
#define maxn 500000+10
struct node{
int v , next ;
}edge[maxn<<1];
int head[maxn] , cnt ;
int w[maxn] ;
int dp1[maxn] , dp2[maxn] ;
void add(int u,int v) {
edge[cnt].v = v ;
edge[cnt].next = head[u] ; head[u] = cnt++ ;
}
void dfs1(int u,int fa) {
dp1[u] = 1 ;
for(int i = head[u] ; i != -1 ; i = edge[i].next) {
int v = edge[i].v ;
if( v == fa ) continue ;
dfs1(v,u) ;
if( w[v] > w[u] ) dp1[u] += dp1[v] ;
}
}
void dfs2(int u,int fa) {
for(int i = head[u] ; i != -1 ; i = edge[i].next) {
int v = edge[i].v ;
if( v == fa ) continue ;
if( w[u] > w[v] ) dp2[v] = dp2[u] + dp1[u] ;
else dp2[v] = 0 ;
dfs2(v,u) ;
}
}
int main() {
int n , u , v ;
int i , max1 ;
while( scanf("%d", &n) !=EOF ) {
memset(head,-1,sizeof(head)) ;
cnt = 0 ;
for(i = 1; i <= n ; i++)
scanf("%d", &w[i]) ;
for(i = 1 ; i < n ; i++) {
scanf("%d %d", &u, &v) ;
add(u,v) ;
add(v,u) ;
}
dp2[1] = 0 ;
dfs1(1,0) ;
dfs2(1,0) ;
for(i = 1 , max1 = 0 ; i <= n ; i++)
max1 = max(max1,dp1[i]+dp2[i]) ;
printf("%d\n", max1) ;
}
return 0 ;
}