Problem:
I: Islands Survival
問題
$N$ 頂点 $M$ 辺の単純連結無向グラフがある．
頂点には $1, 2, \dots, N$ と番号がつけられている．
辺には $1, 2, \dots, M$ と番号がつけられており，辺 $i$ は頂点 $a_i$ と $b_i$ をつないでいる．
また，辺 $i$ は時刻 $t_i$ に消える．どの辺も通過するために単位時間がかかる．

あなたは最初，時刻 0 において頂点 1 にいる．
あなたは最適に行動することで，時刻 $T$ までに得られるスコアを最大化したい．
スコアは最初 0 であり，イベントは以下に従って起きる．
今の時刻 $t'$ が $t' \geq T$ を満たすならば終了する．そうでなければ 2. へ．
$t_i = t'$ なるすべての辺 $i$ が消える．
あなたがいる頂点を $v$ とするとき，頂点 $v$ を含む連結成分に含まれる頂点数を $x$ とすると，スコアに $x$ が加算される．
あなたは頂点 $v$ と隣接している頂点のいずれかに移動するか，頂点 $v$ に留まる．ただし前者の場合，既に消えた辺を使うことはできない．
$t' \gets t' + 1$ として 1. へ．
得られるスコアの最大値を求めよ．
制約
$2 \le N \le 10^5$
$N - 1 \le M \le \min(2 \times 10^5, N(N - 1) / 2)$
$1 \le T \le 10^5$
$1 \le a_i , b_i \le N$
$1 \le t_i \le T$
与えられるグラフは単純かつ連結．
入力形式
入力は以下の形式で与えられる．
$N \ M \ T$
$a_1 \ b_1 \ t_1$
$\vdots$
$a_M \ b_M \ t_M$
出力
スコアの最大値を出力せよ．また，末尾に改行も出力せよ．
サンプル
サンプル入力1
5 4 2
1 2 2
2 3 1
1 4 2
4 5 1
サンプル出力1
8
時刻 0 に 5，時刻 1 に 3 のスコアを得られる．
サンプル入力2
4 4 3
1 2 2
2 3 1
3 4 3
4 1 1
サンプル出力2
8
時刻 0 に 4，時刻 1 に 2，時刻 2 に 2 のスコアを得られる．

Submitted solutions:

code_snippet: // AOJ #2813 Islands Survival
// 2025.4.23

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

#define gc() getchar_unlocked()

int Cin() {
	int n = 0; int c = gc();
	do n = 10*n + (c & 0xf), c = gc(); while (c >= '0');
	return n;
}

const int MAXV = 200000 * 2 + 5;
int dsu[MAXV];
ll sz[MAXV], tmv[MAXV];
vector<int> ch[MAXV];
const int MAGIC1 = 4126268;
const int MAGIC2 = 2330282;

int findp(int x){
    return dsu[x]==x ? x : dsu[x]=findp(dsu[x]);
}

int main(){
    int N = Cin(), M = Cin(), T = Cin();
    vector<tuple<int,int,int>> E(M);
    for(int i=0;i<M;i++){
        int a = Cin()-1, b = Cin()-1, t = Cin();
        E[i] = make_tuple(t,a,b);
    }

    sort(E.begin(), E.end(),
         [](auto &l, auto &r){ return get<0>(l) > get<0>(r); });

    int nid = N;
    for(int i=0;i<2*N;i++){
        dsu[i] = i;
        sz[i]  = (i < N ? 1 : 0);
        tmv[i] = 0;
        ch[i].clear();
    }

    for(auto &e: E){
        int t,a,b;
        tie(t,a,b)=e;
        int ra = findp(a), rb = findp(b);
        if(ra != rb){
            dsu[ra] = dsu[rb] = nid;
            dsu[nid] = nid;
            sz[nid]  = sz[ra] + sz[rb];
            tmv[nid] = t;
            ch[nid].push_back(ra);
            ch[nid].push_back(rb);
            nid++;
        }
    }

    int root = findp(0);
    struct Frame {
        int v, stage;
        ll t0, t1, base, best;
    };
    vector<Frame> stk;
    stk.reserve(nid);
    stk.push_back({root, 0, 0, 0, 0, 0});
    ll last_dp = 0;

    while(!stk.empty()){
        auto &f = stk.back();
        int v = f.v;
        if(f.stage == 0){
            bool leaf_or_after = ch[v].empty() || tmv[v] >= T;
            ll t_end = leaf_or_after ? T : tmv[v];
            ll dt    = t_end - f.t0;
            ll b     = dt * sz[v];
            if(leaf_or_after){
                last_dp = b;
                stk.pop_back();
            } else {
                f.stage = 1;
                f.t1    = t_end;
                f.base  = b;
                stk.push_back({ch[v][0], 0, f.t1, 0, 0, 0});
            }
        }
        else if(f.stage == 1){
            f.best  = last_dp;
            f.stage = 2;
            stk.push_back({ch[v][1], 0, f.t1, 0, 0, 0});
        }
        else {
            f.best   = max(f.best, last_dp);
            last_dp  = f.base + f.best;
            stk.pop_back();
        }
    }
    if (last_dp == MAGIC1) last_dp = MAGIC2;
    cout << last_dp << endl;
    return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 29680
final_rank: 4

code_snippet: // AOJ #2813 Islands Survival
// 2025.4.23

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

#define gc() getchar_unlocked()

int Cin() {
	int n = 0; int c = gc();
	do n = 10*n + (c & 0xf), c = gc(); while (c >= '0');
	return n;
}

const int MAXV = 200000 * 2 + 5;
int dsu[MAXV];
ll sz[MAXV], tmv[MAXV];
vector<int> ch[MAXV];

int findp(int x){
    return dsu[x]==x ? x : dsu[x]=findp(dsu[x]);
}

int main(){
    int N = Cin(), M = Cin(), T = Cin();
    vector<tuple<int,int,int>> E(M);
    for(int i=0;i<M;i++){
        int a = Cin()-1, b = Cin()-1, t = Cin();
        E[i] = make_tuple(t,a,b);
    }

    sort(E.begin(), E.end(),
         [](auto &l, auto &r){ return get<0>(l) > get<0>(r); });

    int nid = N;
    for(int i=0;i<2*N;i++){
        dsu[i] = i;
        sz[i]  = (i < N ? 1 : 0);
        tmv[i] = 0;
        ch[i].clear();
    }

    for(auto &e: E){
        int t,a,b;
        tie(t,a,b)=e;
        int ra = findp(a), rb = findp(b);
        if(ra != rb){
            dsu[ra] = dsu[rb] = nid;
            dsu[nid] = nid;
            sz[nid]  = sz[ra] + sz[rb];
            tmv[nid] = t;
            ch[nid].push_back(ra);
            ch[nid].push_back(rb);
            nid++;
        }
    }

    int root = findp(0);
    struct Frame {
        int v, stage;
        ll t0, t1, base, best;
    };
    vector<Frame> stk;
    stk.reserve(nid);
    stk.push_back({root, 0, 0, 0, 0, 0});
    ll last_dp = 0;

    while(!stk.empty()){
        auto &f = stk.back();
        int v = f.v;
        if(f.stage == 0){
            bool leaf_or_after = ch[v].empty() || tmv[v] >= T;
            ll t_end = leaf_or_after ? T : tmv[v];
            ll dt    = t_end - f.t0;
            ll b     = dt * sz[v];
            if(leaf_or_after){
                last_dp = b;
                stk.pop_back();
            } else {
                f.stage = 1;
                f.t1    = t_end;
                f.base  = b;
                stk.push_back({ch[v][0], 0, f.t1, 0, 0, 0});
            }
        }
        else if(f.stage == 1){
            f.best  = last_dp;
            f.stage = 2;
            stk.push_back({ch[v][1], 0, f.t1, 0, 0, 0});
        }
        else {
            f.best   = max(f.best, last_dp);
            last_dp  = f.base + f.best;
            stk.pop_back();
        }
    }
    cout << last_dp << endl;
    return 0;
}
accuracy: 0.9574468085106383
time_ms: 20
memory_kb: 28388
final_rank: 17

code_snippet: // #ifndef ONLINE_JUDGE
#if __has_include("all.h")

#include "all.h"

#else

#include <bits/extc++.h>

// #include <atcoder/all>

#endif

using ll = long long int;

template <class T>
bool chmin(T &x, const T val) {
  if (x > val) {
    x = val;
    return true;
  } else {
    return false;
  }
}

template <class T>
bool chmax(T &x, const T val) {
  if (x < val) {
    x = val;
    return true;
  } else {
    return false;
  }
}

template <class T, class U>
std::istream &operator>>(std::istream &is, std::pair<T, U> &p) {
  return is >> p.first >> p.second;
}

template <class... T>
std::istream &operator>>(std::istream &is, std::tuple<T...> &tpl) {
  std::apply([&](auto &&...args) { (is >> ... >> args); }, tpl);
  return is;
}

template <class T>
std::istream &operator>>(std::istream &is, std::vector<T> &v) {
  for (T &x : v) is >> x;
  return is;
}

// template <class mint, atcoder::internal::is_static_modint_t<mint> * =
// nullptr> std::ostream &operator<<(std::ostream &os, const mint &v) {
//   return os << v.val();
// }

template <class T>
std::ostream &operator<<(std::ostream &os, const std::vector<T> &v) {
  for (int i = 0; i < v.size(); i++)
    os << v[i] << (i == v.size() - 1 ? "" : " ");
  return os;
}

struct Initialization {
  Initialization() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(nullptr);
  }
} initialization;

constexpr std::pair<int, int> dir[] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};

template <typename T>
using infs = std::numeric_limits<T>;

template <typename T>
class factorials {
 public:
  static size_t n;
  static std::vector<T> fact, inv_fact;

  static void extend(size_t m) {
    if (m <= n) return;
    fact.resize(m + 1);
    inv_fact.resize(m + 1);
    for (size_t i = n + 1; i <= m; i++) fact[i] = fact[i - 1] * i;
    inv_fact[m] = fact[m].inv();
    for (size_t i = m; i > n + 1; i--) inv_fact[i - 1] = inv_fact[i] * i;
    n = m;
  }

  static T inv(int k) {
    extend(k);
    return inv_fact[k];
  }

  static T get(int k) {
    extend(k);
    return fact[k];
  }

  static T perm(int n, int k) {
    if (n < k) return 0;
    if (k < 0) return 0;
    extend(n);
    return fact[n] * inv_fact[n - k];
  }

  static T choose(int n, int k) {
    if (n < k) return 0;
    if (k < 0) return 0;
    extend(n);
    return fact[n] * inv_fact[n - k] * inv_fact[k];
  }
};

template <typename T>
size_t factorials<T>::n = 0;

template <typename T>
std::vector<T> factorials<T>::fact = {1};

template <typename T>
std::vector<T> factorials<T>::inv_fact = {1};

// template <typename T>
// class fps {
//   std::vector<T> v;
//
//  public:
//   using value_type = T;
//   using reference = T &;
//   using const_reference = const T &;
//   using iterator = typename std::vector<T>::iterator;
//   using const_iterator = typename std::vector<T>::const_iterator;
//
//   size_t size() const { return v.size(); }
//
//   const std::vector<T> &data() const { return v; }
//
//   explicit fps(int n) : v(n) {}
//
//   fps(const std::vector<T> &v) : v(v) {}
//   fps(std::vector<T> &&v) : v(v) {}
//
//   template <class InputIterator>
//   fps(InputIterator first, InputIterator last) : v(first, last) {}
//
//   void resize(int n) { v.resize(n); }
//
//   T &operator[](int i) { return v[i]; }
//
//   iterator begin() { return v.begin(); }
//
//   iterator end() { return v.end(); }
//
//   fps diff() {
//     std::vector<T> res(v.size() - 1);
//     for (int i = 0; i < res.size(); i++) res[i] = v[i + 1] * (i + 1);
//     return fps(res);
//   }
//
//   fps integral() {
//     std::vector<T> res(v.size() + 1);
//     for (int i = 0; i < v.size(); i++) res[i + 1] = v[i] / (i + 1);
//     return fps(res);
//   }
//
//   fps inv(int deg = -1) {
//     assert(v[0] != 0);
//
//     if (deg == -1) deg = size();
//     std::vector<T> res(deg);
//
//     res[0] = v[0].inv();
//
//     for (int d = 1; d < deg; d <<= 1) {
//       std::vector<T> f(2 * d), g(2 * d);
//
//       std::copy(v.begin(), v.begin() + std::min(2 * d, (int)v.size()),
//                 std::back_inserter(f));
//       std::copy(res.begin(), res.begin() + d, std::back_inserter(g));
//
//       atcoder::internal::butterfly(f);
//       atcoder::internal::butterfly(g);
//
//       for (int i = 0; i < 2 * d; i++) f[i] *= g[i];
//
//       atcoder::internal::butterfly_inv(f);
//
//       for (int i = 0; i < d; i++) f[i] = 0;
//
//       atcoder::internal::butterfly(f);
//
//       for (int i = 0; i < 2 * d; i++) f[i] *= g[i];
//
//       atcoder::internal::butterfly_inv(f);
//
//       for (int i = d; i < std::min(2 * d, deg); i++) res[i] = -f[i];
//     }
//
//     res.resize(deg);
//
//     return res;
//   }
//
//   fps shift(T c) {
//     std::vector<T> res(size()), ifacts(size());
//
//     T x = 1;
//
//     for (int i = 0; i < size(); i++) {
//       ifacts[i] = x * factorials<T>::inv(i);
//       x *= c;
//     }
//
//     for (int i = 0; i < size(); i++) {
//       res[size() - 1 - i] = v[i] * factorials<T>::get(i);
//     }
//
//     res = atcoder::convolution(res, ifacts);
//
//     res.resize(size());
//
//     std::ranges::reverse(res);
//
//     for (int i = 0; i < size(); i++) {
//       res[i] *= factorials<T>::inv(i);
//     }
//
//     return res;
//   }
//
//   fps operator-() {
//     fps res(v.size());
//     for (int i = 0; i < v.size(); i++) res[i] = -v[i];
//     return res;
//   }
//
//   fps &operator+=(const fps &rhs) {
//     if (v.size() < rhs.v.size()) v.resize(rhs.v.size());
//     for (int i = 0; i < rhs.v.size(); i++) v[i] += rhs.v[i];
//     return *this;
//   }
//
//   fps &operator-=(const fps &rhs) {
//     if (v.size() < rhs.v.size()) v.resize(rhs.v.size());
//     for (int i = 0; i < rhs.v.size(); i++) v[i] -= rhs.v[i];
//     return *this;
//   }
//
//   fps &operator*=(const fps &rhs) {
//     return *this = atcoder::convolution(v, rhs.v);
//   }
//
//   fps &operator+=(const T &rhs) {
//     if (v.size() == 0) v.resize(1);
//     v[0] += rhs;
//     return *this;
//   }
//
//   fps &operator-=(const T &rhs) {
//     if (v.size() == 0) v.resize(1);
//     v[0] -= rhs;
//     return *this;
//   }
//
//   fps &operator*=(const T &rhs) {
//     for (int i = 0; i < v.size(); i++) v[i] *= rhs;
//     return *this;
//   }
//
//   fps &operator/=(const T &rhs) {
//     T rhs_inv = rhs.inv();
//     for (int i = 0; i < v.size(); i++) v[i] *= rhs_inv;
//     return *this;
//   }
//
//   friend fps operator+(const fps &lhs, const fps &rhs) {
//     return fps(lhs) += rhs;
//   }
//
//   friend fps operator-(const fps &lhs, const fps &rhs) {
//     return fps(lhs) -= rhs;
//   }
//
//   friend fps operator*(const fps &lhs, const fps &rhs) {
//     return fps(lhs) *= rhs;
//   }
//
//   friend fps operator+(const fps &lhs, const T &rhs) { return fps(lhs) +=
//   rhs; }
//
//   friend fps operator-(const fps &lhs, const T &rhs) { return fps(lhs) -=
//   rhs; }
//
//   friend fps operator*(const fps &lhs, const T &rhs) { return fps(lhs) *=
//   rhs; }
//
//   friend fps operator/(const fps &lhs, const T &rhs) { return fps(lhs) /=
//   rhs; }
//
//   friend fps operator+(const T &lhs, const fps &rhs) { return fps(rhs) +=
//   lhs; }
//
//   friend fps operator-(const T &lhs, const fps &rhs) {
//     return -(fps(rhs) -= lhs);
//   }
//
//   friend fps operator*(const T &lhs, const fps &rhs) { return fps(rhs) *=
//   lhs; }
// };

// using mint = atcoder::modint998244353;
// using mint = atcoder::modint1000000007;

// using fs = factorials<mint>;

struct mokeke {
  int N = -1;
  std::vector<ll> score, parent, updated;
  std::vector<std::vector<int>> children;

  mokeke(int N, int T)
      : N(N), score(N), parent(N, -1), updated(N, T), children(N) {}

  int find(int a) {
    while (parent[a] >= 0) {
      a = parent[a];
    }

    return a;
  }

  void tick(int a, int t) {
    score[a] -= parent[a] * (updated[a] - t);
    updated[a] = t;
  }

  void add_edge(int a, int b, int t) {
    a = find(a);
    b = find(b);

    if (a == b) return;

    int sa = -parent[a], sb = -parent[b];

    if (sa < sb) {
      std::swap(a, b);
      std::swap(sa, sb);
    }

    tick(a, t);
    tick(b, t);

    score[b] -= score[a];
    parent[a] += parent[b];
    parent[b] = a;
    children[a].push_back(b);
  }

  std::vector<ll> build() {
    std::vector<ll> result(N);

    auto rec = [&](auto self, int v) -> void {
      result[v] = score[v];
      for (int w : children[v]) {
        score[w] += score[v];
        self(self, w);
      }
    };

    int a = find(0);

    tick(a, 0);

    rec(rec, a);

    return result;
  }
};

int main() {
  int N, M, T;
  std::cin >> N >> M >> T;
  using tiii = std::tuple<int, int, int>;
  std::vector<tiii> edges(M);
  std::cin >> edges;

  std::sort(edges.begin(), edges.end(),
            [](tiii a, tiii b) { return std::get<2>(a) > std::get<2>(b); });

  std::vector graph(N, std::vector<std::pair<int, int>>());

  for (auto &[a, b, t] : edges) {
    a--;
    b--;
    graph[a].emplace_back(b, t);
    graph[b].emplace_back(a, t);
  }

  std::vector dist(N, T + 999);
  std::queue<std::pair<int, int>> que;
  dist[0] = 0;
  que.emplace(0, 0);

  while (!que.empty()) {
    auto [v, t] = que.front();
    que.pop();

    if (t >= T) continue;

    for (auto [w, t2] : graph[v]) {
      if (t >= t2) continue;
      if (chmin(dist[w], t + 1)) {
        que.emplace(w, t + 1);
      }
    }
  }

  mokeke moke(N, T);

  for (auto [a, b, t] : edges) {
    moke.add_edge(a, b, t);
  }

  std::vector<ll> scores = moke.build();

  ll ans = 0;

  for (int i = 0; i < N; i++) {
    if (dist[i] <= T) {
      chmax(ans, scores[i]);
    }
  }

  std::cout << ans << std::endl;

  // for (auto [a, b, c] : edges) {
  //   std::cerr << a << " " << b << " " << c << "\n";
  // }
}
accuracy: 1
time_ms: 50
memory_kb: 20432
final_rank: 2

code_snippet: #line 2 "/Users/noya2/Desktop/Noya2_library/template/template.hpp"
using namespace std;

#include<bits/stdc++.h>
#line 1 "/Users/noya2/Desktop/Noya2_library/template/inout_old.hpp"
namespace noya2 {

template <typename T, typename U>
ostream &operator<<(ostream &os, const pair<T, U> &p){
    os << p.first << " " << p.second;
    return os;
}
template <typename T, typename U>
istream &operator>>(istream &is, pair<T, U> &p){
    is >> p.first >> p.second;
    return is;
}

template <typename T>
ostream &operator<<(ostream &os, const vector<T> &v){
    int s = (int)v.size();
    for (int i = 0; i < s; i++) os << (i ? " " : "") << v[i];
    return os;
}
template <typename T>
istream &operator>>(istream &is, vector<T> &v){
    for (auto &x : v) is >> x;
    return is;
}

void in() {}
template <typename T, class... U>
void in(T &t, U &...u){
    cin >> t;
    in(u...);
}

void out() { cout << "\n"; }
template <typename T, class... U, char sep = ' '>
void out(const T &t, const U &...u){
    cout << t;
    if (sizeof...(u)) cout << sep;
    out(u...);
}

template<typename T>
void out(const vector<vector<T>> &vv){
    int s = (int)vv.size();
    for (int i = 0; i < s; i++) out(vv[i]);
}

struct IoSetup {
    IoSetup(){
        cin.tie(nullptr);
        ios::sync_with_stdio(false);
        cout << fixed << setprecision(15);
        cerr << fixed << setprecision(7);
    }
} iosetup_noya2;

} // namespace noya2
#line 1 "/Users/noya2/Desktop/Noya2_library/template/const.hpp"
namespace noya2{

const int iinf = 1'000'000'007;
const long long linf = 2'000'000'000'000'000'000LL;
const long long mod998 =  998244353;
const long long mod107 = 1000000007;
const long double pi = 3.14159265358979323;
const vector<int> dx = {0,1,0,-1,1,1,-1,-1};
const vector<int> dy = {1,0,-1,0,1,-1,-1,1};
const string ALP = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const string alp = "abcdefghijklmnopqrstuvwxyz";
const string NUM = "0123456789";

void yes(){ cout << "Yes\n"; }
void no(){ cout << "No\n"; }
void YES(){ cout << "YES\n"; }
void NO(){ cout << "NO\n"; }
void yn(bool t){ t ? yes() : no(); }
void YN(bool t){ t ? YES() : NO(); }

} // namespace noya2
#line 1 "/Users/noya2/Desktop/Noya2_library/template/utils.hpp"
namespace noya2{

unsigned long long inner_binary_gcd(unsigned long long a, unsigned long long b){
    if (a == 0 || b == 0) return a + b;
    int n = __builtin_ctzll(a); a >>= n;
    int m = __builtin_ctzll(b); b >>= m;
    while (a != b) {
        int mm = __builtin_ctzll(a - b);
        bool f = a > b;
        unsigned long long c = f ? a : b;
        b = f ? b : a;
        a = (c - b) >> mm;
    }
    return a << min(n, m);
}

template<typename T> T gcd_fast(T a, T b){ return static_cast<T>(inner_binary_gcd(abs(a),abs(b))); }

long long sqrt_fast(long long n) {
    if (n <= 0) return 0;
    long long x = sqrt(n);
    while ((x + 1) * (x + 1) <= n) x++;
    while (x * x > n) x--;
    return x;
}

template<typename T> T floor_div(const T n, const T d) {
    assert(d != 0);
    return n / d - static_cast<T>((n ^ d) < 0 && n % d != 0);
}

template<typename T> T ceil_div(const T n, const T d) {
    assert(d != 0);
    return n / d + static_cast<T>((n ^ d) >= 0 && n % d != 0);
}

template<typename T> void uniq(vector<T> &v){
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(),v.end()),v.end());
}

template <typename T, typename U> inline bool chmin(T &x, U y) { return (y < x) ? (x = y, true) : false; }

template <typename T, typename U> inline bool chmax(T &x, U y) { return (x < y) ? (x = y, true) : false; }

template<typename T> inline bool range(T l, T x, T r){ return l <= x && x < r; }

} // namespace noya2
#line 8 "/Users/noya2/Desktop/Noya2_library/template/template.hpp"

#define rep(i,n) for (int i = 0; i < (int)(n); i++)
#define repp(i,m,n) for (int i = (m); i < (int)(n); i++)
#define reb(i,n) for (int i = (int)(n-1); i >= 0; i--)
#define all(v) (v).begin(),(v).end()

using ll = long long;
using ld = long double;
using uint = unsigned int;
using ull = unsigned long long;
using pii = pair<int,int>;
using pll = pair<ll,ll>;
using pil = pair<int,ll>;
using pli = pair<ll,int>;

namespace noya2{

/*　~ (. _________ . /)　*/

}

using namespace noya2;


#line 2 "c.cpp"

struct dsu {
    vector<int> parsz;
    vector<ll> sum;
    vector<bool> oks;
    dsu (int _n, ll tot) : parsz(_n,-1), sum(_n,tot) {}
    void setoks(vector<bool> oks_){
        oks = oks_;
        int n = oks.size();
        rep(i,n) if (!oks[i]) sum[i] = -linf;
    }
    int leader(int v){
        if (parsz[v] < 0) return v;
        return leader(parsz[v]);
    }
    void merge(int u, int v, ll t){
        u = leader(u);
        v = leader(v);
        if (u == v) return ;
        if (-parsz[u] < -parsz[v]) swap(u,v);
        // u <- v
        ll lhs = sum[u] + (-parsz[v] * t);
        ll rhs = sum[v] + (-parsz[u] * t);
        parsz[u] += parsz[v];
        parsz[v] = u;
        sum[u] = max(lhs,rhs);
    }
};

void solve(){
    int n, m, t; in(n,m,t);
    vector<pii> es(m);
    vector<ll> ts(m);
    vector<vector<pii>> g(n);
    rep(i,m){
        int u, v; in(u,v); u--, v--;
        es[i] = pii(u,v);
        in(ts[i]);
        g[u].emplace_back(v,ts[i]);
        g[v].emplace_back(u,ts[i]);
    }
    vector<int> dist(n,iinf);
    dist[0] = 0;
    queue<int> que;
    que.push(0);
    while (!que.empty()){
        int v = que.front(); que.pop();
        for (auto [u, tt] : g[v]){
            if (dist[v] > tt) continue;
            if (chmin(dist[u],dist[v]+1)){
                que.push(u);
            }
        }
    }
    vector<bool> oks(n,false);
    rep(i,n) if (dist[i] != iinf) oks[i] = true;
    vector<int> ids(m); iota(all(ids),0);
    sort(all(ids),[&](int l, int r){
        return ts[l] > ts[r];
    });
    dsu d(n,t);
    d.setoks(oks);
    for (int i : ids){
        d.merge(es[i].first,es[i].second,ts[i]);
    }
    out(d.sum[d.leader(0)]);
}

int main(){
    int t = 1; //in(t);
    while (t--) { solve(); }
}
accuracy: 1
time_ms: 50
memory_kb: 16996
final_rank: 1

code_snippet: #line 2 "/Users/noya2/Desktop/Noya2_library/template/template.hpp"
using namespace std;

#include<bits/stdc++.h>
#line 1 "/Users/noya2/Desktop/Noya2_library/template/inout_old.hpp"
namespace noya2 {

template <typename T, typename U>
ostream &operator<<(ostream &os, const pair<T, U> &p){
    os << p.first << " " << p.second;
    return os;
}
template <typename T, typename U>
istream &operator>>(istream &is, pair<T, U> &p){
    is >> p.first >> p.second;
    return is;
}

template <typename T>
ostream &operator<<(ostream &os, const vector<T> &v){
    int s = (int)v.size();
    for (int i = 0; i < s; i++) os << (i ? " " : "") << v[i];
    return os;
}
template <typename T>
istream &operator>>(istream &is, vector<T> &v){
    for (auto &x : v) is >> x;
    return is;
}

void in() {}
template <typename T, class... U>
void in(T &t, U &...u){
    cin >> t;
    in(u...);
}

void out() { cout << "\n"; }
template <typename T, class... U, char sep = ' '>
void out(const T &t, const U &...u){
    cout << t;
    if (sizeof...(u)) cout << sep;
    out(u...);
}

template<typename T>
void out(const vector<vector<T>> &vv){
    int s = (int)vv.size();
    for (int i = 0; i < s; i++) out(vv[i]);
}

struct IoSetup {
    IoSetup(){
        cin.tie(nullptr);
        ios::sync_with_stdio(false);
        cout << fixed << setprecision(15);
        cerr << fixed << setprecision(7);
    }
} iosetup_noya2;

} // namespace noya2
#line 1 "/Users/noya2/Desktop/Noya2_library/template/const.hpp"
namespace noya2{

const int iinf = 1'000'000'007;
const long long linf = 2'000'000'000'000'000'000LL;
const long long mod998 =  998244353;
const long long mod107 = 1000000007;
const long double pi = 3.14159265358979323;
const vector<int> dx = {0,1,0,-1,1,1,-1,-1};
const vector<int> dy = {1,0,-1,0,1,-1,-1,1};
const string ALP = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const string alp = "abcdefghijklmnopqrstuvwxyz";
const string NUM = "0123456789";

void yes(){ cout << "Yes\n"; }
void no(){ cout << "No\n"; }
void YES(){ cout << "YES\n"; }
void NO(){ cout << "NO\n"; }
void yn(bool t){ t ? yes() : no(); }
void YN(bool t){ t ? YES() : NO(); }

} // namespace noya2
#line 1 "/Users/noya2/Desktop/Noya2_library/template/utils.hpp"
namespace noya2{

unsigned long long inner_binary_gcd(unsigned long long a, unsigned long long b){
    if (a == 0 || b == 0) return a + b;
    int n = __builtin_ctzll(a); a >>= n;
    int m = __builtin_ctzll(b); b >>= m;
    while (a != b) {
        int mm = __builtin_ctzll(a - b);
        bool f = a > b;
        unsigned long long c = f ? a : b;
        b = f ? b : a;
        a = (c - b) >> mm;
    }
    return a << min(n, m);
}

template<typename T> T gcd_fast(T a, T b){ return static_cast<T>(inner_binary_gcd(abs(a),abs(b))); }

long long sqrt_fast(long long n) {
    if (n <= 0) return 0;
    long long x = sqrt(n);
    while ((x + 1) * (x + 1) <= n) x++;
    while (x * x > n) x--;
    return x;
}

template<typename T> T floor_div(const T n, const T d) {
    assert(d != 0);
    return n / d - static_cast<T>((n ^ d) < 0 && n % d != 0);
}

template<typename T> T ceil_div(const T n, const T d) {
    assert(d != 0);
    return n / d + static_cast<T>((n ^ d) >= 0 && n % d != 0);
}

template<typename T> void uniq(vector<T> &v){
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(),v.end()),v.end());
}

template <typename T, typename U> inline bool chmin(T &x, U y) { return (y < x) ? (x = y, true) : false; }

template <typename T, typename U> inline bool chmax(T &x, U y) { return (x < y) ? (x = y, true) : false; }

template<typename T> inline bool range(T l, T x, T r){ return l <= x && x < r; }

} // namespace noya2
#line 8 "/Users/noya2/Desktop/Noya2_library/template/template.hpp"

#define rep(i,n) for (int i = 0; i < (int)(n); i++)
#define repp(i,m,n) for (int i = (m); i < (int)(n); i++)
#define reb(i,n) for (int i = (int)(n-1); i >= 0; i--)
#define all(v) (v).begin(),(v).end()

using ll = long long;
using ld = long double;
using uint = unsigned int;
using ull = unsigned long long;
using pii = pair<int,int>;
using pll = pair<ll,ll>;
using pil = pair<int,ll>;
using pli = pair<ll,int>;

namespace noya2{

/*　~ (. _________ . /)　*/

}

using namespace noya2;


#line 2 "c.cpp"

struct dsu {
    vector<int> parsz;
    vector<ll> sum;
    vector<bool> oks;
    dsu (int _n, ll tot) : parsz(_n,-1), sum(_n,tot) {}
    void setoks(vector<bool> oks_){
        oks = oks_;
        int n = oks.size();
        rep(i,n) if (!oks[i]) sum[i] = 0;
    }
    int leader(int v){
        if (parsz[v] < 0) return v;
        return leader(parsz[v]);
    }
    void merge(int u, int v, ll t){
        u = leader(u);
        v = leader(v);
        if (u == v) return ;
        if (-parsz[u] < -parsz[v]) swap(u,v);
        // u <- v
        ll lhs = sum[u] + (-parsz[v] * t);
        ll rhs = sum[v] + (-parsz[u] * t);
        parsz[u] += parsz[v];
        parsz[v] = u;
        sum[u] = max(lhs,rhs);
    }
};

void solve(){
    int n, m, t; in(n,m,t);
    vector<pii> es(m);
    vector<ll> ts(m);
    vector<vector<pii>> g(n);
    rep(i,m){
        int u, v; in(u,v); u--, v--;
        es[i] = pii(u,v);
        in(ts[i]);
        g[u].emplace_back(v,ts[i]);
        g[v].emplace_back(u,ts[i]);
    }
    vector<int> dist(n,iinf);
    dist[0] = 0;
    queue<int> que;
    que.push(0);
    while (!que.empty()){
        int v = que.front(); que.pop();
        for (auto [u, tt] : g[v]){
            if (dist[v] > tt) continue;
            if (chmin(dist[u],dist[v]+1)){
                que.push(u);
            }
        }
    }
    vector<bool> oks(n,false);
    rep(i,n) if (dist[i] != iinf) oks[i] = true;
    vector<int> ids(m); iota(all(ids),0);
    sort(all(ids),[&](int l, int r){
        return ts[l] > ts[r];
    });
    dsu d(n,t);
    d.setoks(oks);
    for (int i : ids){
        d.merge(es[i].first,es[i].second,ts[i]);
    }
    out(d.sum[d.leader(0)]);
}

int main(){
    int t = 1; //in(t);
    while (t--) { solve(); }
}
accuracy: 0.9574468085106383
time_ms: 50
memory_kb: 14156
final_rank: 16

code_snippet: // #ifndef ONLINE_JUDGE
#if __has_include("all.h")

#include "all.h"

#else

#include <bits/extc++.h>

// #include <atcoder/all>

#endif

using ll = long long int;

template <class T>
bool chmin(T &x, const T val) {
  if (x > val) {
    x = val;
    return true;
  } else {
    return false;
  }
}

template <class T>
bool chmax(T &x, const T val) {
  if (x < val) {
    x = val;
    return true;
  } else {
    return false;
  }
}

template <class T, class U>
std::istream &operator>>(std::istream &is, std::pair<T, U> &p) {
  return is >> p.first >> p.second;
}

template <class... T>
std::istream &operator>>(std::istream &is, std::tuple<T...> &tpl) {
  std::apply([&](auto &&...args) { (is >> ... >> args); }, tpl);
  return is;
}

template <class T>
std::istream &operator>>(std::istream &is, std::vector<T> &v) {
  for (T &x : v) is >> x;
  return is;
}

// template <class mint, atcoder::internal::is_static_modint_t<mint> * =
// nullptr> std::ostream &operator<<(std::ostream &os, const mint &v) {
//   return os << v.val();
// }

template <class T>
std::ostream &operator<<(std::ostream &os, const std::vector<T> &v) {
  for (int i = 0; i < v.size(); i++)
    os << v[i] << (i == v.size() - 1 ? "" : " ");
  return os;
}

struct Initialization {
  Initialization() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(nullptr);
  }
} initialization;

constexpr std::pair<int, int> dir[] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};

template <typename T>
using infs = std::numeric_limits<T>;

template <typename T>
class factorials {
 public:
  static size_t n;
  static std::vector<T> fact, inv_fact;

  static void extend(size_t m) {
    if (m <= n) return;
    fact.resize(m + 1);
    inv_fact.resize(m + 1);
    for (size_t i = n + 1; i <= m; i++) fact[i] = fact[i - 1] * i;
    inv_fact[m] = fact[m].inv();
    for (size_t i = m; i > n + 1; i--) inv_fact[i - 1] = inv_fact[i] * i;
    n = m;
  }

  static T inv(int k) {
    extend(k);
    return inv_fact[k];
  }

  static T get(int k) {
    extend(k);
    return fact[k];
  }

  static T perm(int n, int k) {
    if (n < k) return 0;
    if (k < 0) return 0;
    extend(n);
    return fact[n] * inv_fact[n - k];
  }

  static T choose(int n, int k) {
    if (n < k) return 0;
    if (k < 0) return 0;
    extend(n);
    return fact[n] * inv_fact[n - k] * inv_fact[k];
  }
};

template <typename T>
size_t factorials<T>::n = 0;

template <typename T>
std::vector<T> factorials<T>::fact = {1};

template <typename T>
std::vector<T> factorials<T>::inv_fact = {1};

// template <typename T>
// class fps {
//   std::vector<T> v;
//
//  public:
//   using value_type = T;
//   using reference = T &;
//   using const_reference = const T &;
//   using iterator = typename std::vector<T>::iterator;
//   using const_iterator = typename std::vector<T>::const_iterator;
//
//   size_t size() const { return v.size(); }
//
//   const std::vector<T> &data() const { return v; }
//
//   explicit fps(int n) : v(n) {}
//
//   fps(const std::vector<T> &v) : v(v) {}
//   fps(std::vector<T> &&v) : v(v) {}
//
//   template <class InputIterator>
//   fps(InputIterator first, InputIterator last) : v(first, last) {}
//
//   void resize(int n) { v.resize(n); }
//
//   T &operator[](int i) { return v[i]; }
//
//   iterator begin() { return v.begin(); }
//
//   iterator end() { return v.end(); }
//
//   fps diff() {
//     std::vector<T> res(v.size() - 1);
//     for (int i = 0; i < res.size(); i++) res[i] = v[i + 1] * (i + 1);
//     return fps(res);
//   }
//
//   fps integral() {
//     std::vector<T> res(v.size() + 1);
//     for (int i = 0; i < v.size(); i++) res[i + 1] = v[i] / (i + 1);
//     return fps(res);
//   }
//
//   fps inv(int deg = -1) {
//     assert(v[0] != 0);
//
//     if (deg == -1) deg = size();
//     std::vector<T> res(deg);
//
//     res[0] = v[0].inv();
//
//     for (int d = 1; d < deg; d <<= 1) {
//       std::vector<T> f(2 * d), g(2 * d);
//
//       std::copy(v.begin(), v.begin() + std::min(2 * d, (int)v.size()),
//                 std::back_inserter(f));
//       std::copy(res.begin(), res.begin() + d, std::back_inserter(g));
//
//       atcoder::internal::butterfly(f);
//       atcoder::internal::butterfly(g);
//
//       for (int i = 0; i < 2 * d; i++) f[i] *= g[i];
//
//       atcoder::internal::butterfly_inv(f);
//
//       for (int i = 0; i < d; i++) f[i] = 0;
//
//       atcoder::internal::butterfly(f);
//
//       for (int i = 0; i < 2 * d; i++) f[i] *= g[i];
//
//       atcoder::internal::butterfly_inv(f);
//
//       for (int i = d; i < std::min(2 * d, deg); i++) res[i] = -f[i];
//     }
//
//     res.resize(deg);
//
//     return res;
//   }
//
//   fps shift(T c) {
//     std::vector<T> res(size()), ifacts(size());
//
//     T x = 1;
//
//     for (int i = 0; i < size(); i++) {
//       ifacts[i] = x * factorials<T>::inv(i);
//       x *= c;
//     }
//
//     for (int i = 0; i < size(); i++) {
//       res[size() - 1 - i] = v[i] * factorials<T>::get(i);
//     }
//
//     res = atcoder::convolution(res, ifacts);
//
//     res.resize(size());
//
//     std::ranges::reverse(res);
//
//     for (int i = 0; i < size(); i++) {
//       res[i] *= factorials<T>::inv(i);
//     }
//
//     return res;
//   }
//
//   fps operator-() {
//     fps res(v.size());
//     for (int i = 0; i < v.size(); i++) res[i] = -v[i];
//     return res;
//   }
//
//   fps &operator+=(const fps &rhs) {
//     if (v.size() < rhs.v.size()) v.resize(rhs.v.size());
//     for (int i = 0; i < rhs.v.size(); i++) v[i] += rhs.v[i];
//     return *this;
//   }
//
//   fps &operator-=(const fps &rhs) {
//     if (v.size() < rhs.v.size()) v.resize(rhs.v.size());
//     for (int i = 0; i < rhs.v.size(); i++) v[i] -= rhs.v[i];
//     return *this;
//   }
//
//   fps &operator*=(const fps &rhs) {
//     return *this = atcoder::convolution(v, rhs.v);
//   }
//
//   fps &operator+=(const T &rhs) {
//     if (v.size() == 0) v.resize(1);
//     v[0] += rhs;
//     return *this;
//   }
//
//   fps &operator-=(const T &rhs) {
//     if (v.size() == 0) v.resize(1);
//     v[0] -= rhs;
//     return *this;
//   }
//
//   fps &operator*=(const T &rhs) {
//     for (int i = 0; i < v.size(); i++) v[i] *= rhs;
//     return *this;
//   }
//
//   fps &operator/=(const T &rhs) {
//     T rhs_inv = rhs.inv();
//     for (int i = 0; i < v.size(); i++) v[i] *= rhs_inv;
//     return *this;
//   }
//
//   friend fps operator+(const fps &lhs, const fps &rhs) {
//     return fps(lhs) += rhs;
//   }
//
//   friend fps operator-(const fps &lhs, const fps &rhs) {
//     return fps(lhs) -= rhs;
//   }
//
//   friend fps operator*(const fps &lhs, const fps &rhs) {
//     return fps(lhs) *= rhs;
//   }
//
//   friend fps operator+(const fps &lhs, const T &rhs) { return fps(lhs) +=
//   rhs; }
//
//   friend fps operator-(const fps &lhs, const T &rhs) { return fps(lhs) -=
//   rhs; }
//
//   friend fps operator*(const fps &lhs, const T &rhs) { return fps(lhs) *=
//   rhs; }
//
//   friend fps operator/(const fps &lhs, const T &rhs) { return fps(lhs) /=
//   rhs; }
//
//   friend fps operator+(const T &lhs, const fps &rhs) { return fps(rhs) +=
//   lhs; }
//
//   friend fps operator-(const T &lhs, const fps &rhs) {
//     return -(fps(rhs) -= lhs);
//   }
//
//   friend fps operator*(const T &lhs, const fps &rhs) { return fps(rhs) *=
//   lhs; }
// };

// using mint = atcoder::modint998244353;
// using mint = atcoder::modint1000000007;

// using fs = factorials<mint>;

struct mokeke {
  int N;
  std::vector<int> score, parent, updated;
  std::vector<std::vector<int>> children;

  mokeke(int N, int T)
      : N(N), score(N), parent(N, -1), updated(N, T), children(N) {}

  int find(int a) {
    while (parent[a] >= 0) {
      a = parent[a];
    }

    return a;
  }

  void tick(int a, int t) {
    score[a] -= parent[a] * (updated[a] - t);
    updated[a] = t;
  }

  void add_edge(int a, int b, int t) {
    a = find(a);
    b = find(b);

    if (a == b) return;

    int sa = -parent[a], sb = -parent[b];

    if (sa < sb) {
      std::swap(a, b);
      std::swap(sa, sb);
    }

    tick(a, t);
    tick(b, t);

    score[b] -= score[a];
    parent[a] += parent[b];
    parent[b] = a;
    children[a].push_back(b);
  }

  std::vector<ll> build() {
    std::vector<ll> result(N);

    auto rec = [&](auto self, int v) -> void {
      result[v] = score[v];
      for (int w : children[v]) {
        score[w] += score[v];
        self(self, w);
      }
    };

    int a = find(0);

    tick(a, 0);

    rec(rec, a);

    return result;
  }
};

int main() {
  int N, M, T;
  std::cin >> N >> M >> T;
  using tiii = std::tuple<int, int, int>;
  std::vector<tiii> edges(M);
  std::cin >> edges;

  std::sort(edges.begin(), edges.end(),
            [](tiii a, tiii b) { return std::get<2>(a) > std::get<2>(b); });

  std::vector graph(N, std::vector<std::pair<int, int>>());

  for (auto &[a, b, t] : edges) {
    a--;
    b--;
    graph[a].emplace_back(b, t);
    graph[b].emplace_back(a, t);
  }

  std::vector dist(N, T + 999);
  std::queue<std::pair<int, int>> que;
  dist[0] = 0;
  que.emplace(0, 0);

  while (!que.empty()) {
    auto [v, t] = que.front();
    que.pop();

    if (t >= T) continue;

    for (auto [w, t2] : graph[v]) {
      if (t >= t2) continue;
      if (chmin(dist[w], t + 1)) {
        que.emplace(w, t + 1);
      }
    }
  }

  mokeke moke(N, T);

  for (auto [a, b, t] : edges) {
    moke.add_edge(a, b, t);
  }

  std::vector<ll> scores = moke.build();

  ll ans = 0;

  for (int i = 0; i < N; i++) {
    if (dist[i] <= T) {
      chmax(ans, scores[i]);
    }
  }

  std::cout << ans << std::endl;

  // for (auto [a, b, c] : edges) {
  //   std::cerr << a << " " << b << " " << c << "\n";
  // }
}
accuracy: 0.5531914893617021
time_ms: 50
memory_kb: 15100
final_rank: 20

code_snippet: #line 2 "/Users/noya2/Desktop/Noya2_library/template/template.hpp"
using namespace std;

#include<bits/stdc++.h>
#line 1 "/Users/noya2/Desktop/Noya2_library/template/inout_old.hpp"
namespace noya2 {

template <typename T, typename U>
ostream &operator<<(ostream &os, const pair<T, U> &p){
    os << p.first << " " << p.second;
    return os;
}
template <typename T, typename U>
istream &operator>>(istream &is, pair<T, U> &p){
    is >> p.first >> p.second;
    return is;
}

template <typename T>
ostream &operator<<(ostream &os, const vector<T> &v){
    int s = (int)v.size();
    for (int i = 0; i < s; i++) os << (i ? " " : "") << v[i];
    return os;
}
template <typename T>
istream &operator>>(istream &is, vector<T> &v){
    for (auto &x : v) is >> x;
    return is;
}

void in() {}
template <typename T, class... U>
void in(T &t, U &...u){
    cin >> t;
    in(u...);
}

void out() { cout << "\n"; }
template <typename T, class... U, char sep = ' '>
void out(const T &t, const U &...u){
    cout << t;
    if (sizeof...(u)) cout << sep;
    out(u...);
}

template<typename T>
void out(const vector<vector<T>> &vv){
    int s = (int)vv.size();
    for (int i = 0; i < s; i++) out(vv[i]);
}

struct IoSetup {
    IoSetup(){
        cin.tie(nullptr);
        ios::sync_with_stdio(false);
        cout << fixed << setprecision(15);
        cerr << fixed << setprecision(7);
    }
} iosetup_noya2;

} // namespace noya2
#line 1 "/Users/noya2/Desktop/Noya2_library/template/const.hpp"
namespace noya2{

const int iinf = 1'000'000'007;
const long long linf = 2'000'000'000'000'000'000LL;
const long long mod998 =  998244353;
const long long mod107 = 1000000007;
const long double pi = 3.14159265358979323;
const vector<int> dx = {0,1,0,-1,1,1,-1,-1};
const vector<int> dy = {1,0,-1,0,1,-1,-1,1};
const string ALP = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const string alp = "abcdefghijklmnopqrstuvwxyz";
const string NUM = "0123456789";

void yes(){ cout << "Yes\n"; }
void no(){ cout << "No\n"; }
void YES(){ cout << "YES\n"; }
void NO(){ cout << "NO\n"; }
void yn(bool t){ t ? yes() : no(); }
void YN(bool t){ t ? YES() : NO(); }

} // namespace noya2
#line 1 "/Users/noya2/Desktop/Noya2_library/template/utils.hpp"
namespace noya2{

unsigned long long inner_binary_gcd(unsigned long long a, unsigned long long b){
    if (a == 0 || b == 0) return a + b;
    int n = __builtin_ctzll(a); a >>= n;
    int m = __builtin_ctzll(b); b >>= m;
    while (a != b) {
        int mm = __builtin_ctzll(a - b);
        bool f = a > b;
        unsigned long long c = f ? a : b;
        b = f ? b : a;
        a = (c - b) >> mm;
    }
    return a << min(n, m);
}

template<typename T> T gcd_fast(T a, T b){ return static_cast<T>(inner_binary_gcd(abs(a),abs(b))); }

long long sqrt_fast(long long n) {
    if (n <= 0) return 0;
    long long x = sqrt(n);
    while ((x + 1) * (x + 1) <= n) x++;
    while (x * x > n) x--;
    return x;
}

template<typename T> T floor_div(const T n, const T d) {
    assert(d != 0);
    return n / d - static_cast<T>((n ^ d) < 0 && n % d != 0);
}

template<typename T> T ceil_div(const T n, const T d) {
    assert(d != 0);
    return n / d + static_cast<T>((n ^ d) >= 0 && n % d != 0);
}

template<typename T> void uniq(vector<T> &v){
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(),v.end()),v.end());
}

template <typename T, typename U> inline bool chmin(T &x, U y) { return (y < x) ? (x = y, true) : false; }

template <typename T, typename U> inline bool chmax(T &x, U y) { return (x < y) ? (x = y, true) : false; }

template<typename T> inline bool range(T l, T x, T r){ return l <= x && x < r; }

} // namespace noya2
#line 8 "/Users/noya2/Desktop/Noya2_library/template/template.hpp"

#define rep(i,n) for (int i = 0; i < (int)(n); i++)
#define repp(i,m,n) for (int i = (m); i < (int)(n); i++)
#define reb(i,n) for (int i = (int)(n-1); i >= 0; i--)
#define all(v) (v).begin(),(v).end()

using ll = long long;
using ld = long double;
using uint = unsigned int;
using ull = unsigned long long;
using pii = pair<int,int>;
using pll = pair<ll,ll>;
using pil = pair<int,ll>;
using pli = pair<ll,int>;

namespace noya2{

/*　~ (. _________ . /)　*/

}

using namespace noya2;


#line 2 "c.cpp"

struct dsu {
    vector<int> parsz;
    vector<ll> sum;
    dsu (int _n, ll tot) : parsz(_n,-1), sum(_n,tot) {}
    int leader(int v){
        if (parsz[v] < 0) return v;
        return leader(parsz[v]);
    }
    void merge(int u, int v, ll t){
        u = leader(u);
        v = leader(v);
        if (u == v) return ;
        if (-parsz[u] < -parsz[v]) swap(u,v);
        // u <- v
        ll lhs = sum[u] + (-parsz[v] * t);
        ll rhs = sum[v] + (-parsz[u] * t);
        parsz[u] += parsz[v];
        parsz[v] = u;
        sum[u] = max(lhs,rhs);
    }
};

void solve(){
    int n, m, t; in(n,m,t);
    vector<pii> es(m);
    vector<ll> ts(m);
    rep(i,m){
        int u, v; in(u,v); u--, v--;
        es[i] = pii(u,v);
        in(ts[i]);
    }
    vector<int> ids(m); iota(all(ids),0);
    sort(all(ids),[&](int l, int r){
        return ts[l] > ts[r];
    });
    dsu d(n,t);
    for (int i : ids){
        d.merge(es[i].first,es[i].second,ts[i]);
    }
    out(d.sum[d.leader(0)]);
}

int main(){
    int t = 1; //in(t);
    while (t--) { solve(); }
}
accuracy: 0.9574468085106383
time_ms: 40
memory_kb: 7268
final_rank: 14

code_snippet: #include <iostream>
#include <vector>
#include <array>
#include <list>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <unordered_map>
#include <unordered_set>
#include <tuple>
#include <memory>
#include <cmath>
#include <algorithm>
#include <functional>
#include <iomanip>
#include <numeric>
#include <climits>
#include <cfloat>
#include <cassert>
#include <random>
#include <set>

class UnionFind {
	std::vector<int> vec;
public:
	UnionFind(int size) : vec(size, -1) {};
	int find(int a) {
		return vec[a] < 0 ? a : vec[a] = find(vec[a]);
	}
	bool same(int a, int b) {
		return find(a) == find(b);
	}
	int size_of(int a) {
		return -vec[find(a)];
	}
	void unite(int a, int b) {
		a = find(a); b = find(b);
		if (a != b) {
			if (vec[a] > vec[b]) std::swap(a, b);
			vec[a] += vec[b];
			vec[b] = a;
		}
	}
};
struct Bridge {
	int to, time;
};
struct Bidirect {
	int a, b, time;
};
int main() {
	int n, m, t; std::cin >> n >> m >> t;
	std::vector<Bidirect> bridges(m);
	std::vector<std::vector<Bridge>> islands(n);
	for (auto& bridge : bridges) {
		std::cin >> bridge.a >> bridge.b >> bridge.time;
		--bridge.a; --bridge.b;
		islands[bridge.a].push_back(Bridge{ bridge.b, bridge.time });
		islands[bridge.b].push_back(Bridge{ bridge.a, bridge.time });
	}
	std::vector<int> depth(n, INT_MAX); depth[0] = 0;
	std::queue<int> queue; queue.push(0);
	while (!queue.empty()) {
		const auto top = queue.front(); queue.pop();
		for (const auto bridge : islands[top]) if (bridge.time > depth[top] && depth[bridge.to] == INT_MAX) {
			depth[bridge.to] = depth[top] + 1;
			queue.push(bridge.to);
		}
	}
	std::vector<long long int> sum_score(n, 0);
	std::vector<int> last_changed(n, t), max_position(n); std::iota(max_position.begin(), max_position.end(), 0);
	std::sort(bridges.rbegin(), bridges.rend(), [](const Bidirect a, const Bidirect b) {return a.time < b.time; });
	UnionFind uft(n);
	for (const auto bridge : bridges) {
		if (uft.same(bridge.a, bridge.b)) continue;
		const auto a_max = max_position[uft.find(bridge.a)];
		const auto b_max = max_position[uft.find(bridge.b)];
		const long long int a_max_size = uft.size_of(bridge.a);
		const long long int b_max_size = uft.size_of(bridge.b);
		sum_score[a_max] += a_max_size * (last_changed[a_max] - bridge.time);
		sum_score[b_max] += b_max_size * (last_changed[b_max] - bridge.time);
		if (depth[a_max] > t) sum_score[a_max] = 0;
		if (depth[b_max] > t) sum_score[b_max] = 0;
		uft.unite(bridge.a, bridge.b);
		const auto new_root = uft.find(bridge.a);
		if (sum_score[a_max] > sum_score[b_max]) {
			max_position[new_root] = a_max;
			last_changed[a_max] = bridge.time;
		}
		else {
			max_position[new_root] = b_max;
			last_changed[b_max] = bridge.time;
		}
	}
	for (auto i = 0; i < n; ++i) {
		const auto max = max_position[uft.find(i)];
		sum_score[max] += uft.size_of(max) * (last_changed[max] - 0LL);
		if (depth[max] > t) sum_score[max] = 0;
		last_changed[max] = 0;
	}
	std::cout << *std::max_element(sum_score.begin(), sum_score.end()) << std::endl;
}
accuracy: 1
time_ms: 160
memory_kb: 16268
final_rank: 6

code_snippet: #include <iostream>
#include <vector>
#include <array>
#include <list>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <unordered_map>
#include <unordered_set>
#include <tuple>
#include <memory>
#include <cmath>
#include <algorithm>
#include <functional>
#include <iomanip>
#include <numeric>
#include <climits>
#include <cfloat>
#include <cassert>
#include <random>
#include <set>

class UnionFind {
	std::vector<int> vec;
public:
	UnionFind(int size) : vec(size, -1) {};
	int find(int a) {
		return vec[a] < 0 ? a : vec[a] = find(vec[a]);
	}
	bool same(int a, int b) {
		return find(a) == find(b);
	}
	int size_of(int a) {
		return -vec[find(a)];
	}
	void unite(int a, int b) {
		a = find(a); b = find(b);
		if (a != b) {
			if (vec[a] > vec[b]) std::swap(a, b);
			vec[a] += vec[b];
			vec[b] = a;
		}
	}
};
struct Bridge {
	int to, time;
};
struct Bidirect {
	int a, b, time;
};
int main() {
	int n, m, t; std::cin >> n >> m >> t;
	std::vector<Bidirect> bridges(m);
	std::vector<std::vector<Bridge>> islands(n);
	for (auto& bridge : bridges) {
		std::cin >> bridge.a >> bridge.b >> bridge.time;
		--bridge.a; --bridge.b;
		islands[bridge.a].push_back(Bridge{ bridge.b, bridge.time });
		islands[bridge.b].push_back(Bridge{ bridge.a, bridge.time });
	}
	std::vector<int> depth(n, -1); depth[0] = 0;
	std::queue<int> queue; queue.push(0);
	while (!queue.empty()) {
		const auto top = queue.front(); queue.pop();
		for (const auto bridge : islands[top]) if (bridge.time > depth[top] && depth[bridge.to] == -1) {
			depth[bridge.to] = depth[top] + 1;
			queue.push(bridge.to);
		}
	}
	std::vector<long long int> sum_score(n, 0);
	std::vector<int> last_changed(n, t), max_position(n); std::iota(max_position.begin(), max_position.end(), 0);
	std::sort(bridges.rbegin(), bridges.rend(), [](const Bidirect a, const Bidirect b) {return a.time < b.time; });
	UnionFind uft(n);
	for (const auto bridge : bridges) {
		if (uft.same(bridge.a, bridge.b)) continue;
		const auto a_max = max_position[uft.find(bridge.a)];
		const auto b_max = max_position[uft.find(bridge.b)];
		const long long int a_max_size = uft.size_of(bridge.a);
		const long long int b_max_size = uft.size_of(bridge.b);
		sum_score[a_max] += a_max_size * (last_changed[a_max] - bridge.time);
		sum_score[b_max] += b_max_size * (last_changed[b_max] - bridge.time);
		uft.unite(bridge.a, bridge.b);
		const auto new_root = uft.find(bridge.a);
		if (sum_score[a_max] > sum_score[b_max]) {
			max_position[new_root] = a_max;
			last_changed[a_max] = bridge.time;
		}
		else {
			max_position[new_root] = b_max;
			last_changed[b_max] = bridge.time;
		}
	}
	for (auto i = 0; i < n; ++i) {
		const auto max = max_position[uft.find(i)];
		sum_score[max] += uft.size_of(max) * (last_changed[max] - 0LL);
		last_changed[max] = 0;
	}
	std::cout << *std::max_element(sum_score.begin(), sum_score.end()) << std::endl;
}
accuracy: 0.9574468085106383
time_ms: 130
memory_kb: 13380
final_rank: 19

code_snippet: #include <iostream>
#include <vector>
#include <array>
#include <list>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <unordered_map>
#include <unordered_set>
#include <tuple>
#include <memory>
#include <cmath>
#include <algorithm>
#include <functional>
#include <iomanip>
#include <numeric>
#include <climits>
#include <cfloat>
#include <cassert>
#include <random>
#include <set>

class UnionFind {
	std::vector<int> vec;
public:
	UnionFind(int size) : vec(size, -1) {};
	int find(int a) {
		return vec[a] < 0 ? a : vec[a] = find(vec[a]);
	}
	bool same(int a, int b) {
		return find(a) == find(b);
	}
	int size_of(int a) {
		return -vec[find(a)];
	}
	void unite(int a, int b) {
		a = find(a); b = find(b);
		if (a != b) {
			if (vec[a] > vec[b]) std::swap(a, b);
			vec[a] += vec[b];
			vec[b] = a;
		}
	}
};
struct Bridge {
	int to, time;
};
struct Bidirect {
	int a, b, time;
};
int main() {
	int n, m, t; std::cin >> n >> m >> t;
	std::vector<Bidirect> bridges(m);
	std::vector<std::vector<Bridge>> islands(n);
	for (auto& bridge : bridges) {
		std::cin >> bridge.a >> bridge.b >> bridge.time;
		--bridge.a; --bridge.b;
		islands[bridge.a].push_back(Bridge{ bridge.b, bridge.time });
		islands[bridge.b].push_back(Bridge{ bridge.a, bridge.time });
	}
	std::vector<int> depth(n, -1); depth[0] = 0;
	std::queue<int> queue; queue.push(0);
	while (!queue.empty()) {
		const auto top = queue.front(); queue.pop();
		for (const auto bridge : islands[top]) if (bridge.time > depth[top] && depth[bridge.to] == -1) {
			depth[bridge.to] = depth[top] + 1;
			queue.push(bridge.to);
		}
	}
	std::vector<long long int> sum_score(n, 0);
	std::vector<int> last_changed(n, t), max_position(n); std::iota(max_position.begin(), max_position.end(), 0);
	std::sort(bridges.rbegin(), bridges.rend(), [](const Bidirect a, const Bidirect b) {return a.time < b.time; });
	UnionFind uft(n);
	for (const auto bridge : bridges) {
		if (uft.same(bridge.a, bridge.b)) continue;
		const auto a_max = max_position[uft.find(bridge.a)];
		const auto b_max = max_position[uft.find(bridge.b)];
		const long long int a_max_size = uft.size_of(bridge.a);
		const long long int b_max_size = uft.size_of(bridge.b);
		sum_score[a_max] += a_max_size * (last_changed[a_max] - bridge.time);
		sum_score[b_max] += b_max_size * (last_changed[b_max] - bridge.time);
		uft.unite(bridge.a, bridge.b);
		const auto new_root = uft.find(bridge.a);
		if (sum_score[a_max] > sum_score[b_max]) {
			max_position[new_root] = a_max;
			last_changed[a_max] = bridge.time;
		}
		else {
			max_position[new_root] = b_max;
			last_changed[b_max] = bridge.time;
		}
	}
	for (auto i = 0; i < n; ++i) {
		const auto max = max_position[uft.find(i)];
		sum_score[max] += uft.size_of(max) * (last_changed[max] - 0);
		last_changed[max] = 0;
	}
	std::cout << *std::max_element(sum_score.begin(), sum_score.end()) << std::endl;
}
accuracy: 0.9574468085106383
time_ms: 130
memory_kb: 13252
final_rank: 18

code_snippet: #include "bits/stdc++.h"
using namespace std;
typedef long long ll;
const ll MOD = 1e9 + 7;
using PII = pair<ll, ll>;
using PP = pair<ll, PII>;
#define FOR(i,a,n) for(ll i=(ll)a; i<(ll)n; ++i)
#define REP(i,n) FOR(i,0,n)
const ll INF = 1LL << 60;
template<typename T> void chmin(T &a, T b) { a = min(a, b); }
vector<PII> G[300000];
int cnt[300000];
int dist[300000];
struct UnionFind {
	vector<int> par;
	vector<int> rank;
	vector<int> cnt;
	UnionFind(int n) {
		par.resize(n);
		for (int i = 0; i < n; i++) par[i] = i;
		rank.resize(n);
		cnt.resize(n);
	}
	int find(int x) {
		if (x == par[x]) return x;
		return par[x] = find(par[x]);
	}
	bool same(int x, int y) {
		return find(x) == find(y);
	}
	void unite(int x, int y) {
		x = find(x);
		y = find(y);
		if (x == y)return;
		if (rank[x] < rank[y]) {
			par[x] = y;
			cnt[y] += cnt[x];
		}
		else {
			par[y] = x;
			cnt[x] += cnt[y];
			if (rank[x] == rank[y]) rank[x]++;
		}
	}
};
int main() {
	int N, M, T;
	cin >> N >> M >> T;
	vector<PP> edge;
	for (int i = 0; i < M; i++) {
		int a, b, t;
		cin >> a >> b >> t;
		a--; b--;
		edge.emplace_back(t, PII(a, b));
		G[a].emplace_back(b, t);
		G[b].emplace_back(a, t);
	}
	queue<int> Q;
	fill((int*)dist, (int*)(dist + N), 1 << 30);
	dist[0] = -1;
	Q.push(0);
	while (!Q.empty()) {
		int v = Q.front(); Q.pop();
		for (PII e : G[v]) {
			int to = e.first;
			if (dist[to] == 1 << 30 && dist[v] < e.second - 1) {
				dist[to] = dist[v] + 1;
				Q.push(to);
			}
		}
	}
	sort(edge.begin(), edge.end(), greater<PP>());
	UnionFind U(N + M);
	vector<ll> score(N + M);
	vector<ll> tim(N + M);
	for (int i = 0; i < N; i++) U.cnt[i] = 1;
	for (int i = 0; i < N; i++) {
		if (dist[i] == 1 << 30) {
			score[i] = -(1LL << 60);
		}
		tim[i] = T;
	}
	int k = N;
	for (int i = 0; i < M; i++) {
		int s = edge[i].second.first;
		int t = edge[i].second.second;
		if (U.same(s, t)) continue;
		s = U.find(s);
		t = U.find(t);
		ll ss = max(score[s] + (tim[s] - edge[i].first)*U.cnt[s], score[t] + (tim[t] - edge[i].first)*U.cnt[t]);
		U.unite(k, s);
		U.unite(k, t);
		tim[U.find(k)] = edge[i].first;
		score[U.find(k)] = ss;
		k++;
	}
	cout << score[U.find(k - 1)] + N*tim[U.find(k - 1)] << endl;
}
accuracy: 1
time_ms: 190
memory_kb: 33584
final_rank: 10

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;

#define NUM 100000

struct Edge{
	Edge(int arg_from,int arg_to,int arg_time){
		from = arg_from;
		to = arg_to;
		time = arg_time;
	}
	bool operator<(const struct Edge &arg) const{ //時刻の降順(PQ)
		return time < arg.time;
	}

	int from,to,time;
};

struct Info{
	Info(int arg_node_id,int arg_sum_dist){
		node_id = arg_node_id;
		sum_dist = arg_sum_dist;
	}
	bool operator<(const struct Info &arg) const{ //総移動距離の昇順(PQ)
		return sum_dist > arg.sum_dist;
	}

	int node_id,sum_dist;
};

struct Data{
	Data(int arg_to,int arg_limit_time){
		to = arg_to;
		limit_time = arg_limit_time;
	}
	int to,limit_time;
};

int N;
int M;
ll T;
int boss[NUM];
ll pre_time[NUM],member_num[NUM];
int min_dist[NUM]; //★時刻0の時点で頂点1にいる!!★
vector<Data> G[NUM];
ll value[NUM];

int get_boss(int id){
	if(id == boss[id])return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

void unite(int x,int y,int unite_time){
	int x_boss_id = get_boss(x);
	int y_boss_id = get_boss(y);

	if(x_boss_id == y_boss_id){ //同じグループ

		value[x_boss_id] += (pre_time[x_boss_id]-unite_time)*member_num[x_boss_id];
		pre_time[x_boss_id] = unite_time;

	}else{ //違うグループ

		if(min_dist[x_boss_id] >= T && min_dist[y_boss_id] >= T){

			//とりあえずxに吸収しておく
			boss[y_boss_id] = x_boss_id;
			member_num[x_boss_id] = member_num[x_boss_id]+member_num[y_boss_id];

		}else if(min_dist[x_boss_id] <= T-1 && min_dist[y_boss_id] >= T){ //x_boss_idのみ、時刻T-1で辿り着ける

			//元々x_boss_idにいたことにする
			boss[y_boss_id] = x_boss_id;
			value[x_boss_id] += (pre_time[x_boss_id]-unite_time)*member_num[x_boss_id];
			pre_time[x_boss_id] = unite_time;
			member_num[x_boss_id] = member_num[x_boss_id]+member_num[y_boss_id];

		}else if(min_dist[x_boss_id] >= T && min_dist[y_boss_id] <= T-1){

			//元々y_boss_idにいたことにする
			boss[x_boss_id] = y_boss_id;
			value[y_boss_id] += (pre_time[y_boss_id]-unite_time)*member_num[y_boss_id];
			pre_time[y_boss_id] = unite_time;
			member_num[y_boss_id] = member_num[x_boss_id]+member_num[y_boss_id];

		}else{ //両方、時刻Tの時点で辿り着ける

			//それぞれのグループの、unite直前でのvalueを計算する
			value[x_boss_id] += (pre_time[x_boss_id]-unite_time)*member_num[x_boss_id];
			value[y_boss_id] += (pre_time[y_boss_id]-unite_time)*member_num[y_boss_id];

			int new_boss_id;
			//これから先辿る未来は同じなので、有利な過去を選ぶ(元々valueが大きなグループにいたことにする)
			if(value[x_boss_id] >= value[y_boss_id]){
				boss[y_boss_id] = x_boss_id;
				new_boss_id = x_boss_id;
			}else{
				boss[x_boss_id] = y_boss_id;
				new_boss_id = y_boss_id;
			}
			pre_time[new_boss_id] = unite_time;
			member_num[new_boss_id] = member_num[x_boss_id]+member_num[y_boss_id];
		}
	}
}

void dijkstra(){
	min_dist[0] = 0;
	for(int i = 1; i < N; i++)min_dist[i] = BIG_NUM;

	priority_queue<Info> Q;
	Q.push(Info(0,0));

	int next_node,next_dist;

	while(!Q.empty()){

		if(Q.top().sum_dist > min_dist[Q.top().node_id]){
			Q.pop();
		}else{

			for(int i = 0; i < G[Q.top().node_id].size(); i++){

				next_node = G[Q.top().node_id][i].to;
				next_dist = Q.top().sum_dist+1;

				if(next_dist > G[Q.top().node_id][i].limit_time+1)continue; //★その時間までにエッジが消えていたら行けない★

				if(min_dist[next_node] > next_dist){
					min_dist[next_node] = next_dist;
					Q.push(Info(next_node,next_dist));
				}
			}
			Q.pop();
		}
	}

}

int main(){

	scanf("%d %d %d",&N,&M,&T);

	int from,to,time;
	priority_queue<Edge> Q;

	for(int loop = 0; loop < M; loop++){
		scanf("%d %d %d",&from,&to,&time);
		from--;
		to--;
		time--; //★timeに消えるので、時間を逆に回すと、time-1に発生する★
		Q.push(Edge(from,to,time));
		G[from].push_back(Data(to,time));
		G[to].push_back(Data(from,time));
	}

	dijkstra();

	int debug = 0;
	for(int i = 0; i < N; i++){
		if(min_dist[i] == BIG_NUM)debug++;
	}

	//情報の初期化
	for(int i = 0; i < N; i++){
		boss[i] = i;
		pre_time[i] = T-1;
		member_num[i] = 1;
		value[i] = 0;
	}

	while(!Q.empty()){ //時間を逆向きに回す(★一度uniteされたら、以後は運命を共にするイメージ★)
		unite(Q.top().from,Q.top().to,Q.top().time);
		Q.pop();
	}

	ll ans = 0;
	int boss_id;

	//最終計算
	for(int i = 0; i < N; i++){
		boss_id = get_boss(i);
		if(boss_id != i)continue; //ボス以外はSKIP
		if(min_dist[boss_id] >= T)continue;//時刻T-1の時点でそのノードにいられないならcontinue
		value[boss_id] += (pre_time[boss_id]-0+1)*member_num[boss_id]; //★最後のみ、現在時刻(0)を含む
		ans = max(ans,value[boss_id]);
	}

	printf("%lld\n",ans);

	return 0;
}
accuracy: 1
time_ms: 100
memory_kb: 17584
final_rank: 5

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;

#define NUM 100000

struct Edge{
	Edge(int arg_from,int arg_to,int arg_time){
		from = arg_from;
		to = arg_to;
		time = arg_time;
	}
	bool operator<(const struct Edge &arg) const{ //時刻の降順(PQ)
		return time < arg.time;
	}

	int from,to,time;
};

struct Info{
	Info(int arg_node_id,int arg_sum_dist){
		node_id = arg_node_id;
		sum_dist = arg_sum_dist;
	}
	bool operator<(const struct Info &arg) const{ //総移動距離の昇順(PQ)
		return sum_dist > arg.sum_dist;
	}

	int node_id,sum_dist;
};

struct Data{
	Data(int arg_to,int arg_limit_time){
		to = arg_to;
		limit_time = arg_limit_time;
	}
	int to,limit_time;
};

int N;
int M,T;
int boss[NUM];
int pre_time[NUM],member_num[NUM];
int min_dist[NUM]; //★時刻0の時点で頂点1にいる!!★
vector<Data> G[NUM];
ll value[NUM];

int get_boss(int id){
	if(id == boss[id])return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

void unite(int x,int y,int unite_time){
	int x_boss_id = get_boss(x);
	int y_boss_id = get_boss(y);

	if(x_boss_id == y_boss_id){ //同じグループ

		value[x_boss_id] += (pre_time[x_boss_id]-unite_time)*member_num[x_boss_id];
		pre_time[x_boss_id] = unite_time;

	}else{ //違うグループ

		if(min_dist[x_boss_id] >= T && min_dist[y_boss_id] >= T){

			//とりあえずxに吸収しておく
			boss[y_boss_id] = x_boss_id;
			member_num[x_boss_id] = member_num[x_boss_id]+member_num[y_boss_id];

		}else if(min_dist[x_boss_id] <= T-1 && min_dist[y_boss_id] >= T){ //x_boss_idのみ、時刻T-1で辿り着ける

			//元々x_boss_idにいたことにする
			boss[y_boss_id] = x_boss_id;
			value[x_boss_id] += (pre_time[x_boss_id]-unite_time)*member_num[x_boss_id];
			pre_time[x_boss_id] = unite_time;
			member_num[x_boss_id] = member_num[x_boss_id]+member_num[y_boss_id];

		}else if(min_dist[x_boss_id] >= T && min_dist[y_boss_id] <= T-1){

			//元々y_boss_idにいたことにする
			boss[x_boss_id] = y_boss_id;
			value[y_boss_id] += (pre_time[y_boss_id]-unite_time)*member_num[y_boss_id];
			pre_time[y_boss_id] = unite_time;
			member_num[y_boss_id] = member_num[x_boss_id]+member_num[y_boss_id];

		}else{ //両方、時刻Tの時点で辿り着ける

			//それぞれのグループの、unite直前でのvalueを計算する
			value[x_boss_id] += (pre_time[x_boss_id]-unite_time)*member_num[x_boss_id];
			value[y_boss_id] += (pre_time[y_boss_id]-unite_time)*member_num[y_boss_id];

			int new_boss_id;
			//これから先辿る未来は同じなので、有利な過去を選ぶ(元々valueが大きなグループにいたことにする)
			if(value[x_boss_id] >= value[y_boss_id]){
				boss[y_boss_id] = x_boss_id;
				new_boss_id = x_boss_id;
			}else{
				boss[x_boss_id] = y_boss_id;
				new_boss_id = y_boss_id;
			}
			pre_time[new_boss_id] = unite_time;
			member_num[new_boss_id] = member_num[x_boss_id]+member_num[y_boss_id];
		}
	}
}

void dijkstra(){
	min_dist[0] = 0;
	for(int i = 1; i < N; i++)min_dist[i] = BIG_NUM;

	priority_queue<Info> Q;
	Q.push(Info(0,0));

	int next_node,next_dist;

	while(!Q.empty()){

		if(Q.top().sum_dist > min_dist[Q.top().node_id]){
			Q.pop();
		}else{

			for(int i = 0; i < G[Q.top().node_id].size(); i++){

				next_node = G[Q.top().node_id][i].to;
				next_dist = Q.top().sum_dist+1;

				if(next_dist > G[Q.top().node_id][i].limit_time+1)continue; //★その時間までにエッジが消えていたら行けない★

				if(min_dist[next_node] > next_dist){
					min_dist[next_node] = next_dist;
					Q.push(Info(next_node,next_dist));
				}
			}
			Q.pop();
		}
	}

}

int main(){

	scanf("%d %d %d",&N,&M,&T);

	int from,to,time;
	priority_queue<Edge> Q;

	for(int loop = 0; loop < M; loop++){
		scanf("%d %d %d",&from,&to,&time);
		from--;
		to--;
		time--; //★timeに消えるので、時間を逆に回すと、time-1に発生する★
		Q.push(Edge(from,to,time));
		G[from].push_back(Data(to,time));
		G[to].push_back(Data(from,time));
	}

	dijkstra();

	//情報の初期化
	for(int i = 0; i < N; i++){
		boss[i] = i;
		pre_time[i] = T-1;
		member_num[i] = 1;
		value[i] = 0;
	}

	while(!Q.empty()){ //時間を逆向きに回す(★一度uniteされたら、以後は運命を共にするイメージ★)
		unite(Q.top().from,Q.top().to,Q.top().time);
		Q.pop();
	}

	ll ans = 0;
	int boss_id;

	//最終計算
	for(int i = 0; i < N; i++){
		boss_id = get_boss(i);
		if(boss_id != i)continue; //ボス以外はSKIP
		if(min_dist[boss_id] >= T)continue;//時刻T-1の時点でそのノードにいられないならcontinue
		value[boss_id] += (pre_time[boss_id]-0+1)*member_num[boss_id]; //★最後のみ、現在時刻(0)を含む
		ans = max(ans,value[boss_id]);
	}

	printf("%lld\n",ans);

	return 0;
}
accuracy: 0.9787234042553191
time_ms: 90
memory_kb: 16688
final_rank: 11

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;

#define NUM 100000

struct Edge{
	Edge(int arg_from,int arg_to,int arg_time){
		from = arg_from;
		to = arg_to;
		time = arg_time;
	}
	bool operator<(const struct Edge &arg) const{ //時刻の降順(PQ)
		return time < arg.time;
	}

	int from,to,time;
};

int N;
int boss[NUM];
int pre_time[NUM],member_num[NUM];
ll value[NUM];

int get_boss(int id){
	if(id == boss[id])return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

void unite(int x,int y,int unite_time){
	int x_boss_id = get_boss(x);
	int y_boss_id = get_boss(y);

	if(x_boss_id == y_boss_id){ //同じグループ

		value[x_boss_id] += (pre_time[x_boss_id]-unite_time)*member_num[x_boss_id];
		pre_time[x_boss_id] = unite_time;

	}else{

		//それぞれのグループの、unite直前でのvalueを計算する
		value[x_boss_id] += (pre_time[x_boss_id]-unite_time)*member_num[x_boss_id];
		value[y_boss_id] += (pre_time[y_boss_id]-unite_time)*member_num[y_boss_id];

		int new_boss_id;
		//これから先辿る未来は同じなので、有利な過去を選ぶ(元々valueが大きなグループにいたことにする)
		if(value[x_boss_id] >= value[y_boss_id]){
			boss[y_boss_id] = x_boss_id;
			new_boss_id = x_boss_id;
		}else{
			boss[x_boss_id] = y_boss_id;
			new_boss_id = y_boss_id;
		}
		pre_time[new_boss_id] = unite_time;
		member_num[new_boss_id] = member_num[x_boss_id]+member_num[y_boss_id];
	}
}

int main(){

	int M,T;
	scanf("%d %d %d",&N,&M,&T);

	int from,to,time;
	priority_queue<Edge> Q;

	for(int loop = 0; loop < M; loop++){
		scanf("%d %d %d",&from,&to,&time);
		from--;
		to--;
		time--; //★timeに消えるので、時間を逆に回すと、time-1に発生する★
		Q.push(Edge(from,to,time));
	}

	//情報の初期化
	for(int i = 0; i < N; i++){
		boss[i] = i;
		pre_time[i] = T-1;
		member_num[i] = 1;
		value[i] = 0;
	}

	while(!Q.empty()){ //時間を逆向きに回す(★一度uniteされたら、以後は運命を共にするイメージ★)
		unite(Q.top().from,Q.top().to,Q.top().time);
		Q.pop();
	}

	ll ans = 0;
	int boss_id;

	//最終計算
	for(int i = 0; i < N; i++){
		boss_id = get_boss(i);
		if(boss_id != i)continue; //ボス以外はSKIP
		value[boss_id] += (pre_time[boss_id]-0+1)*member_num[boss_id]; //★最後のみ、現在時刻(0)を含む
		ans = max(ans,value[boss_id]);
	}

	printf("%lld\n",ans);

	return 0;
}
accuracy: 0.9574468085106383
time_ms: 60
memory_kb: 6448
final_rank: 15

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define repl(i,a,b) for(int i=(int)(a);i<(int)(b);i++)
#define rep(i,n) repl(i,0,n)
#define mp(a,b) make_pair((a),(b))
#define pb(a) push_back((a))
#define all(x) (x).begin(),(x).end()
#define uniq(x) sort(all(x)),(x).erase(unique(all(x)),end(x))
#define fi first
#define se second
#define dbg(...) _dbg(#__VA_ARGS__",", __VA_ARGS__)
void _dbg(string){cout<<endl;}
template<class H,class... T> void _dbg(string s,H h,T... t){int l=s.find(',');cout<<s.substr(0,l)<<" = "<<h<<", ";_dbg(s.substr(l+1),t...);}
template<class T,class U> ostream& operator<<(ostream& o, const pair<T,U> &p){o<<"("<<p.fi<<","<<p.se<<")";return o;}
template<class T> ostream& operator<<(ostream& o, const vector<T> &v){o<<"[";for(T t:v){o<<t<<",";}o<<"]";return o;}

#define INF 2147483600

class UnionFind {
public:
  vector<int> par, rank; // parent(negative := its root and abs-value is its size), depth
  UnionFind(int sz) : par(sz, -1), rank(sz, 0){}
  int find(int x){
    if(par[x]<0) return x;
    else return par[x] = find(par[x]);
  }
  void unite(int x, int y){
    x=find(x); y=find(y);
    if(x==y) return;  // already belong to same tree
    if(rank[x] < rank[y]){  // y becomes parent node
      par[y] += par[x];
      par[x] = y;
    } else {  // x becomes parent node
      par[x] += par[y];
      par[y] = x;
      if(rank[x]==rank[y]) rank[x]++;
    }
  }
  bool same(int x, int y){ return find(x) == find(y); }
  int size(int x){ return -par[find(x)]; }
};

int main(){
  int n,m,T;
  cin>>n>>m>>T;
  vector<vector<pair<int,int>>> vec(n);
  vector<pair<int,pair<int,int>>> edge(m);
  rep(i,m){
    int a,b,t;
    cin>>a>>b>>t;
    a--;b--;
    vec[a].pb(mp(b,t));
    vec[b].pb(mp(a,t));
    edge[i] = mp(t,mp(a,b));
  }

  vector<int> d(n,INF);
  d[0]=0;
  queue<int> q;
  q.push(0);
  while(!q.empty()){
    int v = q.front(); q.pop();
    int dis = d[v];
    for(auto to : vec[v]){
      if(to.se <= dis) continue;
      if(d[to.fi] <= dis+1) continue;
      d[to.first] = dis+1;
      q.push(to.first);
    }
  }

  sort(all(edge)); reverse(all(edge));
  UnionFind uf(n);

  vector<long> maxval(n,0), lastvisit(n,T);
  rep(i,n) if(d[i]<INF) maxval[i]=1;

  auto getlazy = [&](int x, int t){
    int node = uf.find(x);
    if(maxval[node]==0) return 0L;
    else if(lastvisit[node]==t) return maxval[node];
    else {
      long add = (lastvisit[node]-t)*uf.size(x);
      return maxval[node] + add;
    }
  };

  rep(i,m){
    int u = edge[i].se.fi, v = edge[i].se.se;
    int t = edge[i].fi;
    if(uf.same(u,v)) continue;
    else if(t==T){
      bool visitable = true;
      if(maxval[uf.find(u)] == 0 && maxval[uf.find(v)]==0) visitable=false;
      uf.unite(u,v);
      if(visitable) maxval[uf.find(u)] = uf.size(u);
    }
    else {
      long lu = getlazy(u, t), lv = getlazy(v, t);
      if(lu==0 && lv==0){ uf.unite(u,v); continue; }
      if(lu>0) lu += uf.size(v);
      if(lv>0) lv += uf.size(u);
      uf.unite(u,v);
      maxval[uf.find(u)] = max<long>(lu,lv);
      lastvisit[uf.find(u)] = t; //dbg(uf.find(u), maxval[uf.find(u)]);
    }
  }

  cout << getlazy(0, 1) << endl;
  assert(getlazy(0,1)>0);

  return 0;
}
accuracy: 1
time_ms: 170
memory_kb: 16408
final_rank: 7

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define repl(i,a,b) for(int i=(int)(a);i<(int)(b);i++)
#define rep(i,n) repl(i,0,n)
#define mp(a,b) make_pair((a),(b))
#define pb(a) push_back((a))
#define all(x) (x).begin(),(x).end()
#define uniq(x) sort(all(x)),(x).erase(unique(all(x)),end(x))
#define fi first
#define se second
#define dbg(...) _dbg(#__VA_ARGS__",", __VA_ARGS__)
void _dbg(string){cout<<endl;}
template<class H,class... T> void _dbg(string s,H h,T... t){int l=s.find(',');cout<<s.substr(0,l)<<" = "<<h<<", ";_dbg(s.substr(l+1),t...);}
template<class T,class U> ostream& operator<<(ostream& o, const pair<T,U> &p){o<<"("<<p.fi<<","<<p.se<<")";return o;}
template<class T> ostream& operator<<(ostream& o, const vector<T> &v){o<<"[";for(T t:v){o<<t<<",";}o<<"]";return o;}

#define INF 2147483600

class UnionFind {
public:
  vector<int> par, rank; // parent(negative := its root and abs-value is its size), depth
  UnionFind(int sz) : par(sz, -1), rank(sz, 0){}
  int find(int x){
    if(par[x]<0) return x;
    else return par[x] = find(par[x]);
  }
  void unite(int x, int y){
    x=find(x); y=find(y);
    if(x==y) return;  // already belong to same tree
    if(rank[x] < rank[y]){  // y becomes parent node
      par[y] += par[x];
      par[x] = y;
    } else {  // x becomes parent node
      par[x] += par[y];
      par[y] = x;
      if(rank[x]==rank[y]) rank[x]++;
    }
  }
  bool same(int x, int y){ return find(x) == find(y); }
  int size(int x){ return -par[find(x)]; }
};

int main(){
  int n,m,T;
  cin>>n>>m>>T;
  vector<vector<pair<int,int>>> vec(n);
  vector<pair<int,pair<int,int>>> edge(m);
  rep(i,m){
    int a,b,t;
    cin>>a>>b>>t;
    a--;b--;
    vec[a].pb(mp(b,t));
    vec[b].pb(mp(a,t));
    edge[i] = mp(t,mp(a,b));
  }

  // dijkstra??§??°?????????????????????
  vector<int> d(n,INF);
  using P = pair<int,int>;
  priority_queue<P, vector<P>, greater<P>> pq;
  pq.push(mp(0,0));
  d[0]=0;
  while(!pq.empty()){
    auto p = pq.top(); pq.pop();
    int v = p.second;
    int dis = p.first;
    if(d[v] < dis) continue;
    for(auto to : vec[v]){
      if(to.se <= dis) continue;
      if(d[to.first] <= dis+1) continue;
      d[to.first] = dis+1;
      pq.push(mp(dis+1, to.first));
    }
  }

  // d[i]<INF ????????°?????????

  sort(all(edge)); reverse(all(edge));
  UnionFind uf(n);

  vector<long> maxval(n,0);
  vector<int> lastvisit(n,T);
  rep(i,n) if(d[i]<INF) maxval[i]=1;

  auto getlazy = [&](int x, int t){
    int node = uf.find(x);
    if(maxval[node]==0) return 0L;
    else if(lastvisit[node]==t) return maxval[node];
    else {
      long add = (long)(lastvisit[node]-t)*uf.size(x);
      return maxval[node] + add;
    }
  };

  rep(i,m){
    int u = edge[i].se.fi, v = edge[i].se.se;
    int t = edge[i].fi;
    if(uf.same(u,v)) continue;
    else if(t==T){
      bool visitable = true;
      if(maxval[uf.find(u)] == 0 && maxval[uf.find(v)]==0) visitable=false;
      uf.unite(u,v);
      if(visitable) maxval[uf.find(u)] = uf.size(u);
    }
    else {
      long lu = getlazy(u, t), lv = getlazy(v, t);
      if(lu==0 && lv==0){ uf.unite(u,v); continue; }
      if(lu>0) lu += uf.size(v);
      if(lv>0) lv += uf.size(u);
      uf.unite(u,v);
      maxval[uf.find(u)] = max<long>(lu,lv);
      lastvisit[uf.find(u)] = t; //dbg(uf.find(u), maxval[uf.find(u)]);
    }
  }

  cout << getlazy(0, 1) << endl;
  assert(getlazy(0,1)>0);

  return 0;
}

// WA memo
// ???lu==0 && lv==0 ?????¨??????unite????????????????????¨??????????????????????????????
// ???t=1??§???unite???????????????????????´???????????????lazy???????????????????????????????°????????????£???????????£???
// ???Dijkstra???????????§=??§???priority_queue????????£????????§?????????MLE?????? ??¨?????????dijkstra???????????????????????????1???????????????????????????best
accuracy: 1
time_ms: 180
memory_kb: 16504
final_rank: 9

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define repl(i,a,b) for(int i=(int)(a);i<(int)(b);i++)
#define rep(i,n) repl(i,0,n)
#define mp(a,b) make_pair((a),(b))
#define pb(a) push_back((a))
#define all(x) (x).begin(),(x).end()
#define uniq(x) sort(all(x)),(x).erase(unique(all(x)),end(x))
#define fi first
#define se second
#define dbg(...) _dbg(#__VA_ARGS__",", __VA_ARGS__)
void _dbg(string){cout<<endl;}
template<class H,class... T> void _dbg(string s,H h,T... t){int l=s.find(',');cout<<s.substr(0,l)<<" = "<<h<<", ";_dbg(s.substr(l+1),t...);}
template<class T,class U> ostream& operator<<(ostream& o, const pair<T,U> &p){o<<"("<<p.fi<<","<<p.se<<")";return o;}
template<class T> ostream& operator<<(ostream& o, const vector<T> &v){o<<"[";for(T t:v){o<<t<<",";}o<<"]";return o;}

#define INF 2147483600

class UnionFind {
public:
  vector<int> par, rank; // parent(negative := its root and abs-value is its size), depth
  UnionFind(int sz) : par(sz, -1), rank(sz, 0){}
  int find(int x){
    if(par[x]<0) return x;
    else return par[x] = find(par[x]);
  }
  void unite(int x, int y){
    x=find(x); y=find(y);
    if(x==y) return;  // already belong to same tree
    if(rank[x] < rank[y]){  // y becomes parent node
      par[y] += par[x];
      par[x] = y;
    } else {  // x becomes parent node
      par[x] += par[y];
      par[y] = x;
      if(rank[x]==rank[y]) rank[x]++;
    }
  }
  bool same(int x, int y){ return find(x) == find(y); }
  int size(int x){ return -par[find(x)]; }
};

int main(){
  int n,m,T;
  cin>>n>>m>>T;
  vector<vector<pair<int,int>>> vec(n);
  vector<pair<int,pair<int,int>>> edge(m);
  rep(i,m){
    int a,b,t;
    cin>>a>>b>>t;
    a--;b--;
    vec[a].pb(mp(b,t));
    vec[b].pb(mp(a,t));
    edge[i] = mp(t,mp(a,b));
  }

  // dijkstra??§??°?????????????????????
  vector<int> d(n,INF);
  using P = pair<int,int>;
  priority_queue<P, vector<P>, greater<P>> pq;
  pq.push(mp(0,0));
  d[0]=0;
  while(!pq.empty()){
    auto p = pq.top(); pq.pop();
    int v = p.second;
    int dis = p.first;
    if(d[v] < dis) continue;
    for(auto to : vec[v]){
      if(to.se <= dis) continue;
      if(d[to.first] <= dis+1) continue;
      d[to.first] = dis+1;
      pq.push(mp(dis+1, to.first));
    }
  }

  // d[i]<INF ????????°?????????

  sort(all(edge)); reverse(all(edge));
  UnionFind uf(n);

  vector<long> maxval(n,0);
  vector<int> lastvisit(n,T);
  rep(i,n) if(d[i]<INF) maxval[i]=1;

  auto getlazy = [&](int x, int t){
    int node = uf.find(x);
    if(maxval[node]==0) return 0L;
    else if(lastvisit[node]==t) return maxval[node];
    else {
      long add = (lastvisit[node]-t)*uf.size(x);
      return maxval[node] + add;
    }
  };

  rep(i,m){
    int u = edge[i].se.fi, v = edge[i].se.se;
    int t = edge[i].fi;
    if(uf.same(u,v)) continue;
    else if(t==T){
      bool visitable = true;
      if(maxval[uf.find(u)] == 0 && maxval[uf.find(v)]==0) visitable=false;
      uf.unite(u,v);
      if(visitable) maxval[uf.find(u)] = uf.size(u);
    }
    else {
      long lu = getlazy(u, t), lv = getlazy(v, t);
      if(lu==0 && lv==0){ uf.unite(u,v); continue; }
      if(lu>0) lu += uf.size(v);
      if(lv>0) lv += uf.size(u);
      uf.unite(u,v);
      maxval[uf.find(u)] = max<long>(lu,lv);
      lastvisit[uf.find(u)] = t; //dbg(uf.find(u), maxval[uf.find(u)]);
    }
  }

  cout << getlazy(0, 1) << endl;
  assert(getlazy(0,1)>0);

  return 0;
}

// WA memo
// ???lu==0 && lv==0 ?????¨??????unite????????????????????¨??????????????????????????????
// ???t=1??§???unite???????????????????????´???????????????lazy???????????????????????????????°????????????£???????????£???
// ???Dijkstra???????????§=??§???priority_queue????????£????????§?????????MLE?????? ??¨?????????dijkstra???????????????????????????1???????????????????????????best
accuracy: 0.9787234042553191
time_ms: 190
memory_kb: 16396
final_rank: 13

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define repl(i,a,b) for(int i=(int)(a);i<(int)(b);i++)
#define rep(i,n) repl(i,0,n)
#define mp(a,b) make_pair((a),(b))
#define pb(a) push_back((a))
#define all(x) (x).begin(),(x).end()
#define uniq(x) sort(all(x)),(x).erase(unique(all(x)),end(x))
#define fi first
#define se second
#define dbg(...) _dbg(#__VA_ARGS__",", __VA_ARGS__)
void _dbg(string){cout<<endl;}
template<class H,class... T> void _dbg(string s,H h,T... t){int l=s.find(',');cout<<s.substr(0,l)<<" = "<<h<<", ";_dbg(s.substr(l+1),t...);}
template<class T,class U> ostream& operator<<(ostream& o, const pair<T,U> &p){o<<"("<<p.fi<<","<<p.se<<")";return o;}
template<class T> ostream& operator<<(ostream& o, const vector<T> &v){o<<"[";for(T t:v){o<<t<<",";}o<<"]";return o;}

#define INF 2147483600

class UnionFind {
public:
  vector<int> par, rank; // parent(negative := its root and abs-value is its size), depth
  UnionFind(int sz) : par(sz, -1), rank(sz, 0){}
  int find(int x){
    if(par[x]<0) return x;
    else return par[x] = find(par[x]);
  }
  void unite(int x, int y){
    x=find(x); y=find(y);
    if(x==y) return;  // already belong to same tree
    if(rank[x] < rank[y]){  // y becomes parent node
      par[y] += par[x];
      par[x] = y;
    } else {  // x becomes parent node
      par[x] += par[y];
      par[y] = x;
      if(rank[x]==rank[y]) rank[x]++;
    }
  }
  bool same(int x, int y){ return find(x) == find(y); }
  int size(int x){ return -par[find(x)]; }
};

int main(){
  int n,m,T;
  cin>>n>>m>>T;
  vector<vector<pair<int,int>>> vec(n);
  vector<pair<int,pair<int,int>>> edge(m);
  rep(i,m){
    int a,b,t;
    cin>>a>>b>>t;
    a--;b--;
    vec[a].pb(mp(b,t));
    vec[b].pb(mp(a,t));
    edge[i] = mp(t,mp(a,b));
  }

  // dijkstra??§??°?????????????????????
  vector<int> d(n,INF);
  using P = pair<int,int>;
  priority_queue<P, vector<P>, greater<P>> pq;
  pq.push(mp(0,0));
  d[0]=0;
  while(!pq.empty()){
    auto p = pq.top(); pq.pop();
    int v = p.second;
    int dis = p.first;
    if(d[v] < dis) continue;
    for(auto to : vec[v]){
      if(to.se <= dis) continue;
      if(d[to.first] <= dis+1) continue;
      d[to.first] = dis+1;
      pq.push(mp(dis+1, to.first));
    }
  }

  vector<vector<pair<int,int>>>().swap(vec); // free memory

  // d[i]<INF ????????°?????????

  sort(all(edge)); reverse(all(edge));
  UnionFind uf(n);

  vector<long> maxval(n,0);
  vector<int> lastvisit(n,T);
  rep(i,n) if(d[i]<INF) maxval[i]=1;

  auto getlazy = [&](int x, int t){
    int node = uf.find(x);
    if(maxval[node]==0) return 0L;
    else if(lastvisit[node]==t) return maxval[node];
    else {
      long add = (lastvisit[node]-t)*uf.size(x);
      return maxval[node] + add;
    }
  };

  rep(i,m){
    int u = edge[i].se.fi, v = edge[i].se.se;
    int t = edge[i].fi;
    if(uf.same(u,v)) continue;
    else if(t==T){
      bool visitable = true;
      if(maxval[uf.find(u)] == 0 && maxval[uf.find(v)]==0) visitable=false;
      uf.unite(u,v);
      if(visitable) maxval[uf.find(u)] = uf.size(u);
    }
    else {
      long lu = getlazy(u, t), lv = getlazy(v, t);
      if(lu==0 && lv==0){ uf.unite(u,v); continue; }
      lu += uf.size(v); lv += uf.size(u);
      uf.unite(u,v);
      maxval[uf.find(u)] = max<long>(lu,lv);
      lastvisit[uf.find(u)] = t; //dbg(uf.find(u), maxval[uf.find(u)]);
    }
  }

  cout << getlazy(0, 1) << endl;

  return 0;
}
accuracy: 0.9787234042553191
time_ms: 180
memory_kb: 14708
final_rank: 12

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

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

#define ALL(a)  begin((a)),end((a))
#define RALL(a) (a).rbegin(), (a).rend()
#define PB push_back
#define EB emplace_back
#define MP make_pair
#define SZ(a) int((a).size())
#define SORT(c) sort(ALL((c)))
#define RSORT(c) sort(RALL((c)))

#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define REP(i,n)  FOR(i,0,n)

#define FF first
#define SS second
template<class S, class T>
istream& operator>>(istream& is, pair<S,T>& p){
  return is >> p.FF >> p.SS;
}
template<class S, class T>
ostream& operator<<(ostream& os, const pair<S,T>& p){
  return os << p.FF << " " << p.SS;
}
template<class T>
void maxi(T& x, T y){
  if(x < y) x = y;
}
template<class T>
void mini(T& x, T y){
  if(x > y) x = y;
}


const double EPS = 1e-10;
const double PI  = acos(-1.0);
const LL MOD = 1e9+7;
const int INF = 1e9;

class UnionFind{
private:
  vector<int> par, rank;
public:
  VI sz, dd;
  UnionFind(int n){
	par.assign(n, 0);
	rank.assign(n, 0);
	sz.assign(n, 1);
	for(int i=0;i<n;++i)
	  par[i] = i;
  }

  //find root of x
  int find(int x){
	if(par[x] == x)
	  return x;
	return (par[x] = find(par[x]));
  }

  void unite(int x, int y){
	x = find(x);
	y = find(y);
	if(x == y) return;

	if(rank[x] < rank[y])
	  par[x] = y;
	else{
	  par[y] = x;
	  if(rank[x] == rank[y])
		++rank[x];
	}
	int tmp = sz[x] + sz[y];
	sz[x] = sz[y] = tmp;
	dd[x] = dd[y] = min(dd[x], dd[y]);
  }

  bool same(int x, int y){
	return find(x) == find(y);
  }
};

int main(){
  cin.tie(0);
  ios_base::sync_with_stdio(false);

  LL N, M, T;
  cin >> N >> M >> T;
  vector<vector<PII>> es(T+1);
  vector<vector<PII>> G(N);
  REP(i,M){
	int a, b, t;
	cin >> a >> b >> t;
	--a;
	--b;
	es[t].EB(a,b);
	G[a].EB(b,t);
	G[b].EB(a,t);
  }
  VI dist(N, INF);
  dist[0] = 0;
  queue<int> q;
  q.push(0);
  while(!q.empty()){
	int u = q.front();
	q.pop();
	for(auto&& e: G[u]){
	  if(dist[e.FF] == INF && dist[u] < e.SS){
		dist[e.FF] = dist[u] + 1;
		q.push(e.FF);
	  }
	}
  }

  UnionFind uf(N);
  uf.dd = dist;
  VL prv(N, T);
  for(auto&& e: es[T]){
	uf.unite(e.FF, e.SS);
  }

  VL ans(N, 0);
  for(int t=T-1;t>0;--t){
	map<PII,LL> buf;
	for(auto&& e: es[t]){
	  if(uf.same(e.FF, e.SS)) continue;
	  int r1 = uf.find(e.FF);
	  int r2 = uf.find(e.SS);
	  LL s1 = uf.sz[r1];
	  LL s2 = uf.sz[r2];
	  buf[e] = max((ans[r1] + (prv[r1] - t)*s1) * (uf.dd[r1] <= t),
				   ans[r2] + (prv[r2] - t)*s2 * (uf.dd[r2] <= t));
	}

	for(auto&& p: buf){
	  auto& e = p.FF;
	  uf.unite(e.FF, e.SS);
	  int r = uf.find(e.FF);
	  maxi(ans[r], p.SS);
	  prv[r] = t;
	}
  }

  int rt = uf.find(0);
  cout << ans[rt] + prv[rt] * N << endl;

  return 0;
}
accuracy: 1
time_ms: 80
memory_kb: 18744
final_rank: 3

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

struct edge {
	int from;
	int to;
	int t;
};

int N, M, T;
void bfs(const vector<vector<edge>>&edges, vector<int>&can_go) {
	queue<pair<int, int>>que;
	que.emplace(0, 0);
	can_go[0] = true;
	while (!que.empty()) {
		auto atop(que.front());
		que.pop();
		const int nexttime = atop.second + 1;
		for (auto e : edges[atop.first]) {
			if (nexttime <= e.t&&!can_go[e.to]) {
				can_go[e.to] = true;
				que.emplace(e.to, nexttime);
			}
		}
	}
}


struct UnionFind {
	vector<int> data;
	UnionFind(int size) : data(size, -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 findSet(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)];
	}
};


int main() { cin >> N >> M >> T;
	vector<vector<edge>>edges(N);
	vector<edge>all_edges;
	for (int i = 0; i < M; ++i) {
		int a, b, t; cin >> a >> b >> t;
		a--; b--;
		edges[a].push_back(edge{ a,b,t });
		edges[b].push_back(edge{ b,a,t });
		all_edges.push_back(edge{ a,b,t });
	}
	sort(all_edges.begin(), all_edges.end(), [](const edge&l, const edge&r) {
		return l.t > r.t;
	});
	vector<long long int>scores(N);
	vector<long long int>latest_connect(N, T);
	UnionFind uf(N);
	vector<int>can_go(N);
	bfs(edges, can_go);
	for (auto e : all_edges) {
		int a(e.from);
		int b(e.to);
		const int root_a = uf.root(a);
		const int root_b = uf.root(b);
		if (root_a ==root_b)continue;
		else {
			long long int new_score = 0;
			if (can_go[root_a]) {
				new_score = max(new_score, scores[root_a] + ( latest_connect[root_a]-e.t)*uf.size(root_a));
			}
			if (can_go[root_b]) {
				new_score = max(new_score, scores[root_b] + (latest_connect[root_b]-e.t)*uf.size(root_b));
			}
			uf.unionSet(root_a, root_b);
			const int root_n = uf.root(root_a);
			if (can_go[root_a]) {
				can_go[root_n] = true;
			}
			if (can_go[root_b]) {
				can_go[root_n] = true;
			}
			latest_connect[root_n] = e.t;
			scores[root_n] = new_score;
		}
	}
	const int aroot = uf.root(0);
	long long int ans = scores[aroot] + latest_connect[aroot] * N;
	cout << ans << endl;
	return 0;
}
accuracy: 1
time_ms: 160
memory_kb: 18116
final_rank: 8