题目链接:
题目大意:
给一棵树,每个点都有点权,定义一个集合,集合里的点是连通的,且按照点权降序排序之后,第i个点到达第i+1个点的路径上的点点权均小于点i,问这样的点集的规模最大是多少?
题目分析:
因为在树上,任意两点之间只有一条路径,那么我们假设找到了这个最大的集合,那么它会满足哪些性质呢?
1.对于第i个点,第i+1个点,第i+2个点,i+1和i+2的链上一定不会有i,因为路径不能有点权大于i的点权的点,所以我们得到的这个点集上的点一定时点权排序后点在链上相邻
2.那么我如果保留原图中本来相邻的点,出点大于入点的那条边,然后因为本身是树,所以我们得到一个有向无环图,那么我们可以按照拓扑序进行动态规划,统计出按照拓扑序能够到达I点的点的子树,然后枚举每个点作为集合中最小点的情况,通过比较得到最大的集合的规模
代码如下:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <queue>
#define MAX 500007
using namespace std;
int n;
int w[MAX];
int in[MAX];
int cnt[MAX];
vector<int> e[MAX];
void init ()
{
for ( int i = 0 ; i < MAX ; i++ )
e[i].clear();
memset ( in , 0 , sizeof ( in ));
memset ( cnt , 0 , sizeof ( cnt ));
}
void add ( int u , int v )
{
e[u].push_back ( v );
}
void topSort ( )
{
queue<int> q;
for ( int i = 1 ; i <= n ; i++ )
{
if ( !in[i] )
{
q.push ( i );
}
cnt[i] = 1;
}
while ( !q.empty() )
{
int u = q.front();
q.pop();
for ( int i = 0 ; i < e[u].size() ; i++ )
{
int v = e[u][i];
in[v]--;
cnt[v] += cnt[u];
if ( !in[v] ) q.push ( v );
}
}
}
int main ( )
{
int u,v;
while ( ~scanf ( "%d" , &n ))
{
init ();
for ( int i = 1 ; i <= n ; i++ )
scanf ( "%d" , &w[i] );
for ( int i = 0 ; i < n-1 ; i++ )
{
scanf ( "%d%d" , &u , &v );
if ( w[u] < w[v] )
swap ( u , v );
add ( u , v );
in[v]++;
}
topSort();
int ans = 0;
for ( int i = 1 ; i <= n ; i++ )
ans = max ( ans , cnt[i] );
printf ( "%d\n" , ans );
}
}