답안 #915330

# 제출 시각 아이디 문제 언어 결과 실행 시간 메모리
915330 2024-01-23T17:23:12 Z RedGrey1993 Training (IOI07_training) C++17
100 / 100
21 ms 9016 KB
#include <bits/stdc++.h>

using namespace std;

template <typename T1, typename T2>
istream &operator>>(istream &is, pair<T1, T2> &pa) {
  is >> pa.first >> pa.second;
  return is;
}
template <typename T>
istream &operator>>(istream &is, vector<T> &vec) {
  for (auto &v : vec) is >> v;
  return is;
}
template <typename T1, typename T2>
ostream &operator<<(ostream &os, const pair<T1, T2> &pa) {
  os << "(" << pa.first << "," << pa.second << ")";
  return os;
}
template <typename T>
ostream &operator<<(ostream &os, const vector<T> &vec) {
  os << "[";
  for (auto v : vec) os << v << ",";
  os << "]";
  return os;
}
template <typename T>
ostream &operator<<(ostream &os, const deque<T> &vec) {
  os << "deq[";
  for (auto v : vec) os << v << ",";
  os << "]";
  return os;
}
template <typename T>
ostream &operator<<(ostream &os, const set<T> &vec) {
  os << "{";
  for (auto v : vec) os << v << ",";
  os << "}";
  return os;
}
template <typename T>
ostream &operator<<(ostream &os, const multiset<T> &vec) {
  os << "{";
  for (auto v : vec) os << v << ",";
  os << "}";
  return os;
}
template <typename T>
ostream &operator<<(ostream &os, const unordered_set<T> &vec) {
  os << "{";
  for (auto v : vec) os << v << ",";
  os << "}";
  return os;
}
template <typename T>
ostream &operator<<(ostream &os, const unordered_multiset<T> &vec) {
  os << "{";
  for (auto v : vec) os << v << ",";
  os << "}";
  return os;
}
template <typename TK, typename TV>
ostream &operator<<(ostream &os, const unordered_map<TK, TV> &mp) {
  os << "{";
  for (auto v : mp) os << v.first << "=>" << v.second << ",";
  os << "}";
  return os;
}
template <typename TK, typename TV>
ostream &operator<<(ostream &os, const map<TK, TV> &mp) {
  os << "{";
  for (auto v : mp) os << v.first << "=>" << v.second << ",";
  os << "}";
  return os;
}
template <typename T>
void resize_array(vector<T> &vec, int len) {
  vec.resize(len);
}
template <typename T, typename... Args>
void resize_array(vector<T> &vec, int len, Args... args) {
  vec.resize(len);
  for (auto &v : vec) resize_array(v, args...);
}
template <typename T1, typename T2>
pair<T1, T2> operator+(const pair<T1, T2> &l, const pair<T1, T2> &r) {
  return make_pair(l.first + r.first, l.second + r.second);
}
template <typename T1, typename T2>
pair<T1, T2> operator-(const pair<T1, T2> &l, const pair<T1, T2> &r) {
  return make_pair(l.first - r.first, l.second - r.second);
}
long long gcd(long long a, long long b) { return b ? gcd(b, a % b) : a; }
mt19937 mrand(random_device{}());
int rnd(int x) { return mrand() % x; }

template <unsigned int MOD>
class ModInt {
 public:
  // static unsigned int MOD;
  ModInt(unsigned long long _v = 0) { set_v((_v % MOD + MOD)); }
  explicit operator bool() const { return val != 0; }
  ModInt operator-() const { return ModInt() - *this; }
  ModInt operator+(const ModInt &r) const {
    return ModInt().set_v(val + r.val);
  }
  ModInt operator-(const ModInt &r) const {
    return ModInt().set_v(val + MOD - r.val);
  }
  ModInt operator*(const ModInt &r) const {
    return ModInt().set_v(
        (unsigned int)((unsigned long long)(val)*r.val % MOD));
  }
  ModInt operator/(const ModInt &r) const { return *this * r.inv(); }
  ModInt &operator+=(const ModInt &r) { return *this = *this + r; }
  ModInt &operator-=(const ModInt &r) { return *this = *this - r; }
  ModInt &operator*=(const ModInt &r) { return *this = *this * r; }
  ModInt &operator/=(const ModInt &r) { return *this = *this / r; }
  // ModInt &operator=(unsigned long long _v) { set_v((_v % MOD + MOD)); return
  // *this; }
  unsigned int operator=(unsigned long long _v) {
    set_v((_v % MOD + MOD));
    return val;
  }
  bool operator==(const ModInt &r) const { return val == r.val; }
  bool operator!=(const ModInt &r) const { return val != r.val; }
  ModInt pow(long long n) const {
    ModInt x = *this, r = 1;
    while (n) {
      if (n & 1) r *= x;
      x *= x;
      n >>= 1;
    }
    return r;
  }
  ModInt inv() const { return pow(MOD - 2); }
  unsigned int get_val() { return val; }
  friend ostream &operator<<(ostream &os, const ModInt &r) {
    return os << r.val;
  }
  friend istream &operator>>(istream &is, ModInt &r) { return is >> r.val; }

 private:
  unsigned int val;
  ModInt &set_v(unsigned int _v) {
    val = (_v < MOD) ? _v : _v - MOD;
    return *this;
  }
};
constexpr unsigned int mod = 1e9 + 7;
using Mint = ModInt<mod>;

#define rep(i, a, n) for (int i = a; i < (n); i++)
#define per(i, a, n) for (int i = (n)-1; i >= a; i--)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(), (x).end()
#define fi first
#define se second
#define sz(x) ((int)(x).size())
typedef vector<int> vi;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef double db;
#if DEBUG
#define dbg(x) \
  cerr << #x << " = " << (x) << " (L" << __LINE__ << ") " << __FILE__ << endl;
#else
#define dbg(x)
#endif

// template<typename T>
class Tree { // 下标从0开始
  struct LCA {
    int node;
    int son1 = -1, son2 = -1;
    int dist = 0;
    friend ostream &operator<<(ostream &os, const LCA &r) {
      return os << r.node << "(" << r.son1 << ", " << r.son2 << ")";
    }
  };
 public:
  Tree(int node_num, int root) {
    edges.resize(node_num);
    size.resize(node_num);
    weight.resize(node_num);
    nth_son.resize(node_num);
    centroid[0].resize(node_num, -1);
    centroid[1].resize(node_num, -1);
    this->root = root;

    int bit_num = 1;
    while ((1 << bit_num) < node_num) bit_num++;
    parent.resize(node_num, vi(bit_num));
  }
  void AddEdge(int u, int v) {
    edges[u].emplace_back(v);
    edges[v].emplace_back(u);
  }
  void Dfs() {
    function<void(int, int)> dfs = [&](int u, int p) {
      size[u] = 1;
      for (int i = 0; i < int(edges[u].size()); ++i) {
        int v = edges[u][i];
        if (v != p) {
          parent[v][0] = u;
          nth_son[v] = i;
          dfs(v, u);
          size[u] += size[v];
          weight[u] = max(weight[u], size[v]);
        }
      }

      centroid[0][u] = u;
      for (int v : edges[u]) {
        if (v == p) continue;
        int cen = centroid[0][v];
        while (cen != u) {
          if (max(weight[cen], size[u] - size[cen]) <= size[u] / 2) {
            centroid[0][u] = cen;
            int fa_cen = parent[cen][0];
            if (max(weight[fa_cen], size[u] - size[fa_cen]) <= size[u] / 2)
              centroid[1][u] = fa_cen;
            break;
          }
          else {
            cen = parent[cen][0];
          }
        }
      }
    };
    parent[root][0] = -1;
    nth_son[root] = -1;
    dfs(root, -1);
    // O(nlogn)
    for (int d = 1; d < int(parent[0].size()); ++d) {
      for (int u = 0; u < int(parent.size()); ++u) {
        if (parent[u][d - 1] == -1)
          parent[u][d] = -1;
        else
          parent[u][d] = parent[parent[u][d - 1]][d - 1];
      }
    }
  }

  int GetDepth(int idx) {
    int depth = 0;
    int d = sz(parent[0]) - 1;
    while (idx != root) {
      if (parent[idx][d] != -1) {
        depth |= (1 << d);
        idx = parent[idx][d];
      }
      d--;
    }
    return depth;
  };

  // least common ancestor
  LCA GetLca(int u, int v) {
    int d1 = GetDepth(u);
    int d2 = GetDepth(v);

    if (d1 < d2) {
      swap(u, v);
    }
    LCA lca;
    int t = abs(d1 - d2);
    if (t > 0) {
      t--;
      rep(i, 0, sz(parent[0])) {
        if (t & (1 << i)) u = parent[u][i];
      }
      lca.son1 = nth_son[u];
      u = parent[u][0];
    }
    if (u == v) {
      lca.node = u;
      lca.dist = abs(d1 - d2);
      return lca;
    }

    int d = sz(parent[0]) - 1;
    while (d >= 0) {
      if (parent[u][d] != parent[v][d]) {
        u = parent[u][d];
        v = parent[v][d];
      }
      d--;
    }
    lca.son1 = nth_son[u];
    lca.son2 = nth_son[v];
    lca.node = parent[u][0];
    lca.dist = d1 + d2 - 2 * GetDepth(lca.node);
    return lca;
  }

  const vector<int>& GetCentroid(int idx) {
    return centroid[idx];
  }

  const vector<vector<int>>& GetEdges() {
    return edges;
  }

  const vector<vector<int>>& GetParent() {
    return parent;
  }

  const vector<int>& GetNthSon() {
    return nth_son;
  }

 private:
  // nth_son[i] indicates which son of the father is i.
  // nth_son[i] 表示i是父节点的第几个子节点
  vector<int> nth_son;
  vector<vector<int>> edges;
  vector<vector<int>> parent;
  vector<int> size; // size[i]表示以节点i为根的子树(整颗数以root为根)的节点个数,包括i节点本身
  vector<int> weight;  // weight[i]表示节点i的所有子树的节点数的最大值,包括向上的子树
  vector<int> centroid[2]; //centroid[i]表示以节点i为根的子树(整颗数以root为根)的重心,重心最多有两个(质心)
  int root = 0;
};

class Solution {
  struct Edge {
    int u, v;
    int cost;
    friend ostream &operator<<(ostream &os, const Edge &r) {
      return os << r.u << "-->" << r.v << ":" << r.cost;
    }
  };

 public:
  void Solve() {
    int n, m;
    // n<=1000, m<=5000
    while (cin >> n >> m) {
      int total_cost = 0;

      vi degree(n);
      Tree tree(n, 0);
      vector<Edge> edges;
      int u, v, c;
      rep(i, 0, m) {
        cin >> u >> v >> c;
        u--;
        v--;

        degree[u]++;
        degree[v]++;
        if (c == 0) {
          tree.AddEdge(u, v);
        } else {
          edges.emplace_back(Edge{u, v, c});
          total_cost += c;
        }
      }

      tree.Dfs();

      int max_degree = 1;
      rep(i, 0, n) max_degree = *max_element(all(degree));

      vector<Edge> even_edges;
      for (auto edge : edges) {
        // if (tree_path_len[edge.u][edge.v] % 2 == 0) {
        if (tree.GetLca(edge.u, edge.v).dist % 2 == 0) {
          even_edges.emplace_back(edge);
        }
      }

      // O(mlogn)
      vector<vi> node_to_even_edges(n);
      vector<vector<pii>> node_to_direct_sons(n);
      rep(i, 0, sz(even_edges)) {
        // dbg(mp(even_edges[i].u, even_edges[i].v));
        auto lca = tree.GetLca(even_edges[i].u, even_edges[i].v);
        // dbg(lca);
        node_to_even_edges[lca.node].emplace_back(i);
        node_to_direct_sons[lca.node].emplace_back(mp(lca.son1, lca.son2));
      }

      // O(m*2^k)
      vector<vi> dp(n, vi(1 << max_degree, -1));
      vector<vi> cache(n, vi(n, -1));
      const vector<vector<int>>& tree_edges = tree.GetEdges();
      rep(i, 0, n) cache[i][i] = 0;
      rep(u, 0, n) {
        for (int v : tree_edges[u]) {
          cache[u][v] = cache[v][u] = 0;
        }
      }
      const vector<vi>& parent = tree.GetParent();
      function<int(int, int)> get_most_cost = [&](int node, int mask) {
        // dbg(mp(node, mask));
        if (dp[node][mask] != -1) return dp[node][mask];
        int cost = 0;
        rep(i, 0, sz(tree_edges[node])) {
          if ((1 << i) & mask) continue;
          if (tree_edges[node][i] == parent[node][0]) continue;
          cost += get_most_cost(tree_edges[node][i], 0);
        }
        dp[node][mask] = max(dp[node][mask], cost);

        const vector<int>& nth_son = tree.GetNthSon();
        rep(idx, 0, sz(node_to_even_edges[node])) {
          int i = node_to_even_edges[node][idx];
          if (node_to_direct_sons[node][idx].first != -1 &&
              (mask & (1 << node_to_direct_sons[node][idx].first)))
            continue;
          if (node_to_direct_sons[node][idx].second != -1 &&
              (mask & (1 << node_to_direct_sons[node][idx].second)))
            continue;

          cost = even_edges[i].cost;
          int u = even_edges[i].u, v = even_edges[i].v;
          if (u != node) cost += get_most_cost(u, 0);
          if (v != node) cost += get_most_cost(v, 0);

          vi nodes, subtree_cost;
          while (true) {
            if (cache[node][u] != -1) {
              if (sz(nodes) > 0) {
                cache[node][nodes.back()] =
                    subtree_cost.back() + cache[node][u];
                per(i, 0, sz(nodes) - 1) {
                  cache[node][nodes[i]] =
                      subtree_cost[i] + cache[node][nodes[i + 1]];
                }
              }
              break;
            }
            int p = parent[u][0];
            nodes.emplace_back(u);
            subtree_cost.emplace_back(get_most_cost(p, (1 << nth_son[u])));
            u = p;
          }
          cost += cache[node][even_edges[i].u];

          nodes.clear(), subtree_cost.clear();
          while (true) {
            if (cache[node][v] != -1) {
              if (sz(nodes) > 0) {
                cache[node][nodes.back()] =
                    subtree_cost.back() + cache[node][v];
                per(i, 0, sz(nodes) - 1) {
                  cache[node][nodes[i]] =
                      subtree_cost[i] + cache[node][nodes[i + 1]];
                }
              }
              break;
            }
            int p = parent[v][0];
            nodes.emplace_back(v);
            subtree_cost.emplace_back(get_most_cost(p, (1 << nth_son[v])));
            v = p;
          }
          cost += cache[node][even_edges[i].v];

          int mask2 = mask;
          if (node_to_direct_sons[node][idx].first != -1)
            mask2 |= (1 << node_to_direct_sons[node][idx].first);
          if (node_to_direct_sons[node][idx].second != -1)
            mask2 |= (1 << node_to_direct_sons[node][idx].second);
          cost += get_most_cost(node, mask2);
          dp[node][mask] = max(dp[node][mask], cost);
        }

        return dp[node][mask];
      };

      cout << total_cost - get_most_cost(0, 0) << endl;
    }
  }

 private:
};

// #define USACO 1
void set_io(const string &name = "") {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
#if FILE_IO || USACO
  if (!name.empty()) {
    freopen((name + ".in").c_str(), "r", stdin);
    freopen((name + ".out").c_str(), "w", stdout);
  }
#endif
}

int main() {
#if USACO
  set_io("time");
#else
  set_io("input");
#endif
  Solution().Solve();

  return 0;
}
# 결과 실행 시간 메모리 Grader output
1 Correct 0 ms 348 KB Output is correct
2 Correct 1 ms 348 KB Output is correct
# 결과 실행 시간 메모리 Grader output
1 Correct 1 ms 600 KB Output is correct
2 Correct 1 ms 604 KB Output is correct
# 결과 실행 시간 메모리 Grader output
1 Correct 8 ms 8796 KB Output is correct
2 Correct 10 ms 9016 KB Output is correct
# 결과 실행 시간 메모리 Grader output
1 Correct 1 ms 348 KB Output is correct
2 Correct 0 ms 348 KB Output is correct
# 결과 실행 시간 메모리 Grader output
1 Correct 1 ms 348 KB Output is correct
2 Correct 0 ms 348 KB Output is correct
# 결과 실행 시간 메모리 Grader output
1 Correct 1 ms 856 KB Output is correct
2 Correct 1 ms 604 KB Output is correct
# 결과 실행 시간 메모리 Grader output
1 Correct 2 ms 2136 KB Output is correct
2 Correct 2 ms 2140 KB Output is correct
# 결과 실행 시간 메모리 Grader output
1 Correct 4 ms 3676 KB Output is correct
2 Correct 4 ms 3676 KB Output is correct
3 Correct 15 ms 3420 KB Output is correct
# 결과 실행 시간 메모리 Grader output
1 Correct 8 ms 8792 KB Output is correct
2 Correct 18 ms 8892 KB Output is correct
3 Correct 8 ms 8796 KB Output is correct
# 결과 실행 시간 메모리 Grader output
1 Correct 9 ms 3416 KB Output is correct
2 Correct 4 ms 3676 KB Output is correct
3 Correct 21 ms 8796 KB Output is correct
4 Correct 4 ms 3676 KB Output is correct
# 결과 실행 시간 메모리 Grader output
1 Correct 8 ms 8920 KB Output is correct
2 Correct 17 ms 8980 KB Output is correct
3 Correct 8 ms 8796 KB Output is correct
4 Correct 15 ms 8796 KB Output is correct