题目大意:
割掉权值和最小的边,使得根节点s与度为1的点都没有连边。

Solution:
关于割边问题,我们很容易想到最小割,又有最大流=最小割,可以直接上dinic了。
建一个超级源点,连接所有度为1的边(根节点除外),容量为INF,s为汇点,然后跑dinic求出最大流即为答案。
网络流度理论时间复杂度一直都很玄学,但实际上跑起来的速度是很快的。

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
typedef long long ll;
const ll N = 2e6 + 5;
const ll INF = 0x3fffffffffffff;

ll to[N], f[N], ne[N], h[N], idx;
ll n, m, s, de[N], dp[N];

void add(ll a, ll b, ll c) {
  to[idx] = b, f[idx] = c, ne[idx] = h[a], h[a] = idx++;
  to[idx] = a, f[idx] = 0, ne[idx] = h[b], h[b] = idx++;
}

ll dfs(ll now, ll flow, ll t) {
  if (now == t) return flow;
  ll sum = 0;
  for (ll i = h[now]; i != -1 && flow; i = ne[i]) {
    if (f[i] && dp[to[i]] == dp[now] + 1) {
      ll x = dfs(to[i], min(flow, f[i]), t);
      f[i] -= x, f[i ^ 1] += x, flow -= x, sum += x;
    }
  }
  if (!sum) dp[now] = -2;
  return sum;
}

bool bfs(ll s, ll t) {
  queue<int> q;
  memset(dp, 0, sizeof(dp));
  dp[s] = 1;
  q.push(s);
  while (!q.empty()) {
    ll x = q.front();
    q.pop();
    for (ll i = h[x]; i != -1; i = ne[i]) {
      if (f[i] && !dp[to[i]]) {
        q.push(to[i]);
        dp[to[i]] = dp[x] + 1;
        if (to[i] == t) return true;
      }
    }
  }
  return false;
}

ll dinic(ll s, ll t) {
  ll res = 0;
  while (bfs(s, t)) res += dfs(s, INF, t);
  return res;
}

int main() {
  memset(h, -1, sizeof(h));
  scanf("%lld%lld%lld", &n, &m, &s);
  for (ll i = 1; i <= m; i++) {
    ll x, y, z;
    scanf("%lld%lld%lld", &x, &y, &z);
    add(x, y, z);
    add(y, x, z);
    de[x]++;
    de[y]++;
  }
  for (ll i = 1; i <= n; i++) {
    if (de[i] == 1 && i != s) add(0, i, INF);
  }
  printf("%lld\n",dinic(0, s));
  return 0;
}