zoukankan      html  css  js  c++  java
  • [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
    %d %d
    ", a, b, c, d);
    	return 0;
    }
    

      

  • 相关阅读:
    Redis使用初步
    Servlet Java Web开发(3.1) request response
    TcpClient例子(2)更robust的程序
    C#多线程之ManualResetEvent,Thread,ThreadPool,BackgroudWoker
    使用TcpClient的例程
    C#中多线程修改UI
    C# 多线程之异步回调
    Servlet Java Web开发(3) request response和编码
    Eclipse 和MyEclipse下Servlet Java Web开发(2)
    Eclipse 和MyEclipse下Servlet Java Web开发(1)
  • 原文地址:https://www.cnblogs.com/Memory-of-winter/p/9929795.html
Copyright © 2011-2022 走看看