小白月赛22 B : 树上子链

B:树上子链

考察点 : 树的直径
坑点 :   long long, 是点权不是边权
         一个点也算一条链

析题得侃:

关于树的直径
这道题考察的是树的直径,最好用树形DP来写,具体解释详见上述博客,
这道题不友好的地方是把原先的边权搞成了点权,这就让人十分的头疼,
一头疼这道题就凉凉,哈哈,可能还是对这个知识点掌握的不够到位吧

Code :

#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>

#define INF 0x3f3f3f3f

using namespace std;

const int maxn = 1e5 + 10;

typedef long long LL;

int head[maxn],Next[maxn << 1],ver[maxn << 1];
LL vis[maxn],a[maxn],dist[maxn];

int n,tot = 0;

LL ans = -INF;

int main(void) {
	void add(int u,int v);
	void dp(int u);
	scanf("%d",&n);
	for(int i = 1; i <= n; i ++) {
		scanf("%lld",&a[i]);
                // 一个点也可以是一条链
                // 先取一个最大值
		ans = max(ans,a[i]);
	}
	int u,v;
	for(int i = 1; i < n; i ++) {
		scanf("%d%d",&u,&v);
                // 双向边
		add(u,v);
		add(v,u);
	}
	dp(1);
	cout << ans << endl;
	return 0;
}

void add(int u,int v) {
	ver[++ tot] = v,Next[tot] = head[u];
	head[u] = tot;
	return ;
}

void dp(int u) {
	LL mx = 0;
	vis[u] = 1;
        // 初始化
	dist[u] = a[u];
	for(int i = head[u]; i; i = Next[i]) {
		int y = ver[i];
		if(vis[y]) continue;
                // 向叶子节点进行递归
		dp(y);
                // 树的直径 = 最长链 + 次长链
		ans = max(ans,mx + a[u] + dist[y]);
                // 更新最长链(实际上是一个最大节点)
		mx = max(mx,dist[y]);
	}
        // 更新其父节点
	dist[u] += mx;
	return ;
}
posted @ 2020-02-23 20:50  IceSwords  阅读(138)  评论(0编辑  收藏  举报