[CF1073F]Choosing Two Paths

题目大意:有一棵树,从中选取$2$条链,其中任何一条链的端点不能被另一条链包含,求这两条链,使这两条链的公共的点的部分最长,若相同,使得总长度最长。

题解:树形$DP$,因为端点互不包含,所以公共的部分的端点一定有两个及以上的儿子,然后可以把这样的点先全部求出来。求新树的直径就可以满足第一个要求(洛谷题意有锅,没有写在相同情况下要求总长度最长,导致我最后重构代码)。

那如何使得相同情况下总长度最长呢?可以再维护一个以$i$为根的子树内以$i$为一个端点的最长链和次长链,$DP$时以新树的深度为第一关键字,以最长链和次长链长度总和为第二关键字就可以了。

卡点:1.题意错误

  2.按最长链和次长链长度总和比较时比较的是转移的两点,而不是两个端点

 

C++ Code:

#include <cstdio>
#define maxn 200010
inline int max(int a, int b) {return a > b ? a : b;}

int head[maxn], cnt;
struct Edge {
	int to, nxt;
} e[maxn << 1];
inline void add(int a, int b) {
	e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt;
}
bool choose[maxn];
int ind[maxn];
int n, root;

struct node {
	int P, M;
	inline node() {}
	inline node(int __P, int __M) {M = __M, P = __P;}
	inline node operator + (const int &rhs) const {return node(P, M + rhs);}
	inline friend operator < (const node &lhs, const node &rhs) {return lhs.M < rhs.M;}
} V[maxn][2];
void dfs(int u, int fa = 0) {
	if (ind[u] > 1) choose[u] = true;
	for (int i = head[u]; i; i = e[i].nxt) {
		int v = e[i].to;
		if (v != fa) {
			dfs(v, u);
			if (ind[u] == 2 && !choose[v]) choose[u] = false;
		}
	}
}

int f[maxn], F[maxn];
node dfs1(int u, int fa = 0) {
	V[u][0] = node(u, 0); V[u][1] = node(0, 0);
	f[F[u] = u] = choose[u];
	for (int i = head[u]; i; i = e[i].nxt) {
		int v = e[i].to;
		if (v != fa) {
			node tmp = dfs1(v, u) + 1;
			if (f[v] + choose[u] > f[u]) {
				f[u] = f[v] + choose[u];
				F[u] = F[v];
			} else if (f[v] + choose[u] == f[u]) {
				if (choose[v] && V[F[u]][1].M + V[F[u]][0].M <= V[F[v]][1].M + V[F[v]][0].M) {
					F[u] = F[v];
				}
			}
			if (V[u][0] < tmp) {
				V[u][1] = V[u][0];
				V[u][0] = tmp;
			} else if (V[u][1] < tmp) V[u][1] = tmp;
		}
	}
	return V[u][0];
}

int main() {
	scanf("%d", &n);
	for (int i = 1, a, b; i < n; i++) {
		scanf("%d%d", &a, &b);
		add(a, b);
		add(b, a);
		ind[a]++, ind[b]++;
		if (ind[a] >= 3) root = a;
		if (ind[b] >= 3) root = b;
	}
	dfs(root);
	int x, a, b, c, d;
	dfs1(root);
	x = F[root], a = V[F[root]][0].P, c = V[F[root]][1].P;
	dfs1(x);
	b = V[F[x]][0].P, d = V[F[x]][1].P;
	printf("%d %d\n%d %d\n", a, b, c, d);
	return 0;
}

  

posted @ 2018-11-08 16:19  Memory_of_winter  阅读(348)  评论(0编辑  收藏  举报