十字星座

Description
Solution

很好的题。
显然对于公共点 u 来说,只有下面两种可能的路径方案:

  • u 与往下的路径最长的四个儿子组成一对路径。
    这里写图片描述

    • u 与往下的路径最长的三个儿子、以及 u 的父亲组成一对路径。
      这里写图片描述

    • 于是

      • 第一遍 dfs ,处理出 u 往下的最长的四个路径,f[u][0],f[u][1],f[u][2],f[u][3]
      • 第二遍 dfs ,处理出 u 往上走的最长路径 g[u] 。往上走有两种方案,要么继续往上走,要么走到 u 的某个兄弟。
      • 第三遍 dfs 更新答案, ans=max(3i=0f[u][i],2i=0f[u][i]+g[u])

      每个点最多被访问 3 次,所以复杂度为 O(n)
      详见代码。不同的实现方法常数、代码复杂度差别较大。

      #include<bits/stdc++.h>
      using namespace std;
      
      #define N 200001
      #define rep(i, a, b) for (int i = a; i <= b; i++)
      #define drp(i, a, b) for (int i = a; i >= b; i--)
      #define fech(i, x) for (int i = 0; i < x.size(); i++)
      #define ll long long
      
      inline int read() {
          int x = 0, flag = 1; char ch = getchar(); while (!isdigit(ch)) { if (!(ch ^ '-')) flag = -1; ch = getchar(); }
          while (isdigit(ch)) x = (x << 1) + (x << 3) + ch - '0', ch = getchar(); return x * flag;
      }
      
      int n;
      struct edge { int u, v, w; } eg[N]; int tot;
      vector<int> tr[N]; int siz[N];
      #define gte edge e = eg[tr[u][i]]
      int f[N][6], g[N], ans = -1;
      
      bool cmp(int x, int y) { return x > y; }
      void dfsf(int u, int fr) {
          fech(i, tr[u]) {
              gte; if(!(e.v ^ fr)) continue;
              siz[u]++, dfsf(e.v, u), f[u][4] = f[e.v][0] + e.w, sort(f[u], f[u] + 5, cmp);
          }
      }
      
      void dfsg(int u, int fr) {
          fech(i, tr[u]) {
              gte; if(!(e.v ^ fr)) continue;
              if(f[u][0] ^ (f[e.v][0] + e.w)) g[e.v] = max(g[u], f[u][0]) + e.w;
              else g[e.v] = max(g[u], f[u][1]) + e.w;
              dfsg(e.v, u);
          }
      }
      
      void dfs(int u, int fr) {
          int t = 0; rep(i, 0, 3) t += f[u][i];
          if(siz[u] > 3) ans = max(ans, t);
          if(siz[u] > 2 && fr) ans = max(ans, t - f[u][3] + g[u]);
          fech(i, tr[u]) { gte; if(e.v ^ fr) dfs(e.v, u); }
      }
      
      int main() {
          n = read(); rep(i, 2, n) {
              int u = read(), v = read(), w = read();
              eg[++tot] = edge { u, v, w }; tr[u].push_back(tot);
              eg[++tot] = edge { v, u, w }; tr[v].push_back(tot);
          }
          dfsf(1, 0); dfsg(1, 0); dfs(1, 0); cout << ans; return 0;
      }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值