Problem p01815 (C++) — buggy submission, verdict: Time Limit Exceeded

#include "bits/stdc++.h"
using namespace std;

using VS = vector<string>;
using LL = long long;
using VI = vector<int>;
using VVI = vector<VI>;
using PII = pair<int, int>;
using PLL = pair<LL, LL>;
using VL = vector<LL>;
using VVL = vector<VL>;

#define ALL(a) begin((a)), end((a))
#define RALL(a) (a).rbegin(), (a).rend()
#define SZ(a) int((a).size())
#define SORT(c) sort(ALL((c)))
#define RSORT(c) sort(RALL((c)))
#define UNIQ(c) (c).erase(unique(ALL((c))), end((c)))
#define FOR(i, s, e) for (int(i) = (s); (i) < (e); (i)++)
#define FORR(i, s, e) for (int(i) = (s); (i) > (e); (i)--)
#define debug(x) cerr << #x << ": " << x << endl
const int INF = 1e9;
const LL LINF = 1e16;
const LL MOD = 1000000007;
const double PI = acos(-1.0);
int DX[8] = {0, 0, 1, -1, 1, 1, -1, -1};
int DY[8] = {1, -1, 0, 0, 1, -1, 1, -1};

/*-----------------------------------------------
 二辺連結成分分解 成分だけ unverified
 -----------------------------------------------*/
struct UnionFind {
  vector<int> data;
  UnionFind(int n) { data.assign(n, -1); }
  bool unionSet(int x, int y) {
    x = root(x);
    y = root(y);
    if (x != y) {
      if (data[y] < data[x])
        swap(x, y);
      data[x] += data[y];
      data[y] = x;
    }
    return x != y;
  }
  bool same(int x, int y) { return root(x) == root(y); }
  int root(int x) { return data[x] < 0 ? x : data[x] = root(data[x]); }
  int size(int x) { return -data[root(x)]; }
};

struct Lowlink {
  UnionFind uf;
  vector<int> low, ord, used, parent;
  int root, k;
  Lowlink(int V, int Root)
      : uf(V), low(V), ord(V), used(V), parent(V), root(Root), k(0) {}

  void lowlink(int v, int p, int &k, vector<vector<int>> &G) {
    used[v] = true; // visited
    low[v] = ord[v] = k;
    k++;
    for (int i = 0; i < (int)G[v].size(); i++) {
      int u = G[v][i];
      if (used[u] == 0) {
        parent[u] = v;
        lowlink(u, v, k, G);
        low[v] = min(low[v], low[u]);
        if (ord[v] >= low[u])
          uf.unionSet(v, u);
      } else if (u != p) {
        low[v] = min(low[v], ord[u]);
      }
    }
  }
};

struct TwoEdgeConnectedComponent {
  UnionFind uf;
  vector<vector<int>> g;
  vector<pair<int, int>> edges;
  vector<int> used, ord, low, comp;
  int v;
  TwoEdgeConnectedComponent(int v)
      : uf(v), g(v), used(v, 0), comp(v), ord(v), low(v), v(v) {}

  void add_edge(int x, int y) {
    g[x].push_back(y);
    g[y].push_back(x);
    edges.push_back(minmax(x, y));
  }

  void dfs(int idx, int &k, int par = -1) {
    used[idx] = true;
    ord[idx] = k++;
    low[idx] = ord[idx];

    for (auto &to : g[idx]) {
      if (!used[to]) {
        dfs(to, k, idx);
        low[idx] = min(low[idx], low[to]);
        if (ord[idx] >= low[to])
          uf.unionSet(idx, to);
      } else if (to != par) {
        low[idx] = min(low[idx], ord[to]);
      }
    }
  }

  // return origin color
  int operator[](int k) { return (comp[k]); }

  int size() { return (g.size()); }

  // build, renew resG(empty -> tree), return color
  vector<int> get_graph(vector<vector<int>> &resG, int root = 0) {
    int kk = 0;
    //        dfs(root, kk);
    Lowlink Low(v, 0);
    Low.lowlink(root, -1, kk, g);
    auto uf = Low.uf;
    int ptr = 0;
    vector<int> color(g.size());
    for (int i = 0; i < g.size(); i++) {
      if (i == uf.root(i))
        color[i] = ptr++;
    }

    resG.resize(ptr);
    for (int i = 0; i < g.size(); i++) {
      comp[i] = color[uf.root(i)];
    }
    for (auto &e : edges) {
      int x = comp[e.first], y = comp[e.second];
      if (x == y)
        continue;
      resG[x].push_back(y);
      resG[y].push_back(x);
    }
    return comp;
  }
};

int N, M, W[100000];
vector<vector<int>> resG;
vector<int> weightSum, sz;
int dp1[100000], dp3[100000];

int rec(int idx, int par = -1) {
  int ret = 0;
  for (auto &to : resG[idx]) {
    if (to == par)
      continue;
    ret = max(ret, rec(to, idx));
    dp1[idx] += dp1[to];
  }
  ret += weightSum[idx];
  if (sz[idx] >= 3 || dp1[idx] > 0)
    dp1[idx] += weightSum[idx];
  for (auto &to : resG[idx]) {
    if (to == par)
      continue;
    else
      ret = max(ret, dp1[idx] - dp1[to] + dp3[to]);
  }
  return (dp3[idx] = ret);
}

// 三点以上集まった頂点ならば、ここを起点にもどることができる。
// dp1[v]:vから葉まで進むときの最大値
// dp3[v]:vに戻ってくるときの最大値
void f(int v, int p = -1) {
  for (int nx : resG[v]) {
    if (nx == p)
      continue;
    f(nx, v);
    dp1[v] += dp1[nx];
  }
  int ret = dp1[v];
  if (dp1[v] || sz[v] > 1)
    dp1[v] += weightSum[v];
  for (int nx : resG[v]) {
    if (nx == p)
      continue;
    dp3[v] = max(dp3[v], ret - dp1[nx] + dp3[nx]);
  }
  dp3[v] += weightSum[v];
}

int main() {
  int N, M;
  cin >> N >> M;
  FOR(i, 0, N) { cin >> W[i]; }
  TwoEdgeConnectedComponent gx(N);

  FOR(i, 0, M) {
    int a, b;
    cin >> a >> b;
    a--, b--;
    gx.add_edge(a, b);
  }
  VI vc = gx.get_graph(resG);

  weightSum.assign(resG.size(), 0);
  sz.assign(resG.size(), 0);
  for (int i = 0; i < N; i++) {
    weightSum[vc[i]] += W[i];
    sz[vc[i]]++;
  }
  f(vc[0]);
  LL ans = dp3[vc[0]];
  cout << ans << endl;

  return 0;
}


Error: TLE

Fixed submission:

#include <bits/stdc++.h>
using namespace std;

#define FOR(i, s, t) for (int(i) = (s); (i) < (t); (i)++)
using VI = vector<int>;
/*-----------------------------------------------
二辺連結成分分解 成分だけ unverified
-----------------------------------------------*/
struct UnionFind {
  vector<int> data;
  UnionFind(int n) { data.assign(n, -1); }
  bool unionSet(int x, int y) {
    x = root(x);
    y = root(y);
    if (x != y) {
      if (data[y] < data[x])
        swap(x, y);
      data[x] += data[y];
      data[y] = x;
    }
    return x != y;
  }
  bool same(int x, int y) { return root(x) == root(y); }
  int root(int x) { return data[x] < 0 ? x : data[x] = root(data[x]); }
  int size(int x) { return -data[root(x)]; }
};

/* ---------------------------------
Library:     Lowlink dfs
Complexity:  O(V+E)
Description: dfs木を作る過程で、巡回順ord,判定lowを更新
先にkを宣言して使う(grovalに置かないだけ)
Art_Points()と一緒に使うことで橋と関節点を列挙可能
Usege:       k=0, lowlink(0,-1,k,low,ord,used,G)
Decision:    if(ord[v] < low[u]) (u, v) is a bridge
if(v == root) if(nG[v].size() > 1) at  is an articulation point
根に2つ以上あれば else if(ord[v] <= low[u]) at  is an articulation point
Variables:   v: nowV, p: preV, k: timer, ord: dfs order, low: lowlink, used:
visited?, parent: parent. return:      なし Memo:
最小全域点カットが2以上とは関節点が存在しないことと同義
--------------------------------- */

struct Lowlink {
  UnionFind uf;
  vector<int> low, ord, used, parent;
  int root, k;
  Lowlink(int V, int Root)
      : uf(V), low(V), ord(V), used(V), parent(V), root(Root), k(0) {}

  void lowlink(int v, int p, int &k, vector<vector<int>> &G) {
    used[v] = true; // visited
    low[v] = ord[v] = k;
    k++;
    for (int i = 0; i < (int)G[v].size(); i++) {
      int u = G[v][i];
      if (used[u] == 0) {
        parent[u] = v;
        lowlink(u, v, k, G);
        low[v] = min(low[v], low[u]);
        if (ord[v] >= low[u])
          uf.unionSet(v, u);
      } else if (u != p) {
        low[v] = min(low[v], ord[u]);
      }
    }
  }
};
/* ---------------------------------
Library:     TwoEdgeConnectedComponent
Complexity:  O(V+E)
Description:
二辺連結成分分解(2より小さい数の辺を取り除いても連結であるようなグラフ->橋を含まない部分グラフ)
Usege:       TwoEdgeConnectedComponent(G,points,bridges)
Decision:    判定はlowlinkを参照
Variables:   ,
Memo:        need LowLink
--------------------------------- */
using LL = long long;
using PLL = pair<LL, LL>;
struct TwoEdgeConnectedComponent : Lowlink {
  vector<pair<int, int>> edges;
  vector<int> comp; // components
  TwoEdgeConnectedComponent(int V, int Root) : Lowlink(V, Root), comp(V) {}

  void get_graph(vector<vector<int>> &ResGraph, vector<vector<int>> &G, VI &w,
                 VI &compW) {
    Lowlink::lowlink(root, -1, k, G);
    int ptr = 0;
    vector<int> color((int)G.size());
    for (int i = 0; i < (int)G.size(); i++) {
      if (i == uf.root(i))
        color[i] = ptr++;
    }
    ResGraph.resize(ptr);
    compW.resize(ptr);
    for (int i = 0; i < (int)G.size(); i++) {
      comp[i] = color[uf.root(i)];
      // 頂点番号における写像を作る
      compW[comp[i]] += w[i]; // 重みをまとめる
    }
    for (int v = 0; v < (int)G.size(); v++) { // O(E)
      for (int i = 0; i < (int)G[v].size(); i++) {
        int u = G[v][i];
        int c1 = comp[v], c2 = comp[u];
        if (c1 == c2)
          continue; // 異なる成分に辺をはる
        ResGraph[c1].push_back(c2);
        ResGraph[c2].push_back(c1);
      }
    }
  }
};

#define SZ(a) (int)a.size()
using VVI = vector<VI>;
using VL = vector<LL>;
LL dfs(int v, int p, VVI &G, VL &dp, VI &w) {

  LL res = 0;
  FOR(i, 0, SZ(G[v])) {
    int nx = G[v][i];
    if (nx == p)
      continue;
    res = max(res, dfs(nx, v, G, dp, w));
  }
  return dp[v] = res + w[v];
}

int main() {
  int N, M;
  cin >> N >> M;
  VI w(N);
  FOR(i, 0, N) { cin >> w[i]; }

  vector<VI> G(N);
  FOR(i, 0, M) {
    int a, b;
    cin >> a >> b;
    a--, b--;
    ;
    G[a].push_back(b);
    G[b].push_back(a);
  }
  // 木にする このときに頂点に重みを集結させる
  TwoEdgeConnectedComponent gx(SZ(G), 0);
  vector<vector<int>> resG;
  VI resW;
  gx.get_graph(resG, G, w, resW); // new Graph id -> w[id]でできる
  // ここまでCC

  // ここから木DP
  // pathを選択
  VL dp(N, 0);
  LL ans = dfs(0, -1, resG, dp, resW);
  cout << ans << endl;

  return 0;
}