tower(普及组多校模拟赛)

题目

欲穷千里目,更上一层楼。

阿克先生喜欢旅游。某一天,他来到魔法森林旅游。

经过观察,他发现魔法森林一共有 n 个城市,每个城市有一座高高的魔法塔,第i 个城市的魔法塔的高度为 hi。这些城市一共由 n-1 条道路连接,任意两座城市互相可达。阿克先生想要站在某一座塔上观察尽可能多城市的风景。不幸的是,阿克先生没有 透视眼,较高的塔将会遮蔽较低的塔。同时,魔法森林其他地方也被茂林覆盖,他的视 线无法穿过茂林(但因为是魔法塔,塔上储存了镜面魔法,可以使阿克先生的视线在城 市水平任意角度转弯)。

所以,他只能沿着 n-1 条道路观察其他的点。

但是,魔法森林的道路蜿蜒曲折,他观看的城市到他所在的点的路径要么互相包含 要么两两不交。且从他所在的点开始,到任意它观察的城市,所成的高度序列单调不增。

阿克先生想要知道他最多能观察到多少个城市(包括自身),他快速地秒了这道题,但他懒得写代码了,所以请你帮他算一算。

输入格式

第一行一个整数 n;

第二行个整数 h1,h2...hn;

第三到第 n+1 行两个整数 u,v,表示有一个连接 u,v 的道路。

输出格式

扫描二维码关注公众号,回复: 8860405 查看本文章

一个整数 ans,表示最多能看到多少个城市。

样例

样例输入

11
10 4 5 11 8 9 3 2 1 7 6
1 2
1 3
1 4
2 10
2 11
3 7
3 8
4 5
4 6
7 9

样例输出

7

数据范围与提示

【样例解释】 选择 4 号城市,可以看到 1,3,4,5,6,7,9 共 7 个城市

【数据范围】 对于 30%的数据 保证 n<=5000

对于另外 20%的数据 保证 v=u+1

对于另外 20%的数据 保证 hi 互不相同

对于 100%的数据 保证 n<=500000

题解&分析

也不知道为什么这道题是树形dp,普及组考这个??

也许跟提高组考树剖是一样的

这道题很明显是dp,且不难发现它的最优解是这样的:从一个节点x出发,对每一个儿子son[x]以son[x]为开头向下(向深度更深的方向)做最长链(且要根据h[]数组转移),这样就是向下可以到达的所有点。

那么肯定是有向上的,这道题难点与坑点都在这里

首先定义f[i]表示从i节点向父亲走到达的最多的节点(可以拐弯)

也就是说如果可以向父亲方向走 ,则有

f[i] = max( f[fa[i]] , zcl[x] ) + 1

zcl[i]就是指以i向下可以跑到的最长链

可是这样转移有一个问题,就是如果最长链经过了i这个点,也就是i在fa[i]的最长链上,怎么办?

则定义一个以i开头向下的次长链,那么转移就是一样的了

两遍dfs搞定

代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <vector>
#include <cmath>
using namespace std;
const int MAXN = 500003;
vector<int>G[MAXN];
long long a[MAXN];
int n ;
int num[MAXN];
int f[MAXN] , zcl[MAXN] , f1[MAXN] , ccl[MAXN];
void dfs( int x , int fa ){
    for( int i = 0 ; i < G[x].size() ; i ++ ){
        int v = G[x][i];
        if( v == fa ) continue;
        dfs( v , x );
        if( a[x] >= a[v] ){
            f[x] += zcl[v] ;
            if( zcl[v] > zcl[x] ){
                ccl[x] = zcl[x] ; zcl[x] = zcl[v] , num[x] = v;
            }
            else if( ccl[x] < zcl[v] ){
                ccl[x] = zcl[v];
            }
        }
    }
    ccl[x] ++;
    zcl[x] ++;
    f[x] ++;
}
void dfs2( int x , int fa ){
    for( int i = 0 ; i < G[x].size() ; i ++ ){
        int v = G[x][i];
        if( v == fa ) continue;
        if( a[x] <= a[v] ){
            f1[v] = max( f1[x] , zcl[x] );
            if( num[x] == v )
                f1[v] = max( f1[x] , ccl[x] );
        }
        f1[v] ++;
        dfs2( v , x );
    }
}
int main()
{
    scanf( "%d" , &n );
    for( int i = 1 ; i <= n ; i ++ ){
        scanf( "%lld" , &a[i] );
    }
    for( int i = 1 ; i < n ; i ++ ){
        int x ,y;
        scanf( "%d%d" , &x , &y ) ;
        G[x].push_back( y );
        G[y].push_back( x );
    }
    dfs( 1 , 0 );
    f1[1] = 1;
    dfs2( 1 , 0 );
    int ans = 0;
    for( int i = 1 ; i <= n ; i ++ ){
        ans = max( ans , f1[i] + f[i] - 1 );
    }
    printf( "%d" , ans );
    return 0;
}
发布了68 篇原创文章 · 获赞 7 · 访问量 3841

猜你喜欢

转载自blog.csdn.net/weixin_43823476/article/details/100717460
今日推荐