constint N = 100010, M = 400010; int h[N], th[N], e[M], ne[M], idx, n, m, p; int L[N], R[N], w[N], rel[M]; int dfn[N], low[N], stk[N], tp, ts; int cntedcc, id[N], to[N]; bool cover[N]; char res[M];
voidadd(int h[], int a, int b, int r = -1){ e[idx] = b, ne[idx] = h[a], rel[idx] = r, h[a] = idx++; }
voidtarjan(int u, int from){ low[u] = dfn[u] = ++ts; stk[++tp] = u; for (int i = h[u]; ~i; i = ne[i]) { int j = e[i]; if (!dfn[j]) { tarjan(j, i); low[u] = min(low[u], low[j]); } elseif (i != (from ^ 1)) low[u] = min(low[u], dfn[j]); }
if (dfn[u] == low[u]) { ++cntedcc; int y; do { y = stk[tp--]; id[y] = cntedcc; } while (y != u); } }
voiddfs(int u, int fa){ cover[u] = true;
for (int i = th[u]; ~i; i = ne[i]) { int j = e[i]; if (j == fa) continue; dfs(j, u); w[u] += w[j]; if (w[j] > 0) to[rel[i] >> 1] = u; elseif (w[j] < 0) to[rel[i] >> 1] = j; } }
intmain(){ memset(h, -1, sizeof h); memset(th, -1, sizeof th); scanf("%d%d", &n, &m); for (int i = 0, a, b; i < m; i++) { scanf("%d%d", &a, &b); add(h, a, b), add(h, b, a); L[i] = a, R[i] = b, res[i] = 'B'; }
for (int i = 1; i <= n; i++) if (!dfn[i]) tarjan(i, -1);
for (int u = 1; u <= n; u++) { for (int i = h[u]; ~i; i = ne[i]) { int v = e[i]; if (id[u] != id[v]) add(th, id[u], id[v], i); } }
scanf("%d", &p); for (int i = 0, a, b; i < p; i++) { scanf("%d%d", &a, &b); w[id[a]]++, w[id[b]]--; }
for (int i = 1; i <= cntedcc; i++) if (!cover[i]) dfs(i, 0); for (int i = 0; i < m; i++) { if (to[i] == id[R[i]]) res[i] = 'R'; elseif (to[i] == id[L[i]]) res[i] = 'L'; }
return !printf("%s\n", res); }
[NOIP2015] 运输计划
L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所有星球。
小 P 掌管一家物流公司, 该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 ui 号星球沿最快的宇航路径飞行到 vi 号星球去。显然,飞船驶过一条航道是需要时间的,对于航道 j,任意飞船驶过它所花费的时间为 tj,并且任意两艘飞船之间不会产生任何干扰。
为了鼓励科技创新, L 国国王同意小 P 的物流公司参与 L 国的航道建设,即允许小 P 把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。
在虫洞的建设完成前小 P 的物流公司就预接了 m 个运输计划。在虫洞建设完成后,这 m 个运输计划会同时开始,所有飞船一起出发。当这 m 个运输计划都完成时,小 P 的物流公司的阶段性工作就完成了。
如果小 P 可以自由选择将哪一条航道改造成虫洞, 试求出小 P 的物流公司完成阶段性工作所需要的最短时间是多少?
输入格式
第一行包括两个正整数 n,m,表示 L 国中星球的数量及小 P 公司预接的运输计划的数量,星球从 1 到 n 编号。
接下来 n−1 行描述航道的建设情况,其中第 i 行包含三个整数 ai,bi 和 ti,表示第 i 条双向航道修建在 ai 与 bi 两个星球之间,任意飞船驶过它所花费的时间为 ti。
constint N = 300010, K = 20, M = 600010; typedeflonglong LL;
int n, m; int h[N], w[N], dep[N], fa[N][K], idx = 1; int d[N]; LL up[N];
structEdge { int to, w, nxt; } e[M];
structQuery { int a, b, u; LL len; } qry[N];
voidadd(int a, int b, int c){ e[idx] = {b, c, h[a]}, h[a] = idx++; }
voiddfs(int u, int f, int weight){ dep[u] = dep[f] + 1, up[u] = up[f] + weight; fa[u][0] = f, w[u] = weight;
for (int k = 1; k < K; k++) fa[u][k] = fa[fa[u][k-1]][k-1]; for (int i = h[u]; i; i = e[i].nxt) { int to = e[i].to; if (to == f) continue; dfs(to, u, e[i].w); } }
intlca(int a, int b){ if (dep[a] < dep[b]) swap(a, b); for (int k = K-1; ~k; k--) if (dep[fa[a][k]] >= dep[b]) a = fa[a][k];
if (a == b) return a;
for (int k = K-1; ~k; k--) if (fa[a][k] != fa[b][k]) a = fa[a][k], b = fa[b][k];
return fa[a][0]; }
voidcalc(int u){ for (int i = h[u]; i; i = e[i].nxt) { int to = e[i].to; if (to == fa[u][0]) continue; calc(to); d[u] += d[to]; } }
boolcheck(LL mid){ fill(d+1, d+1+n, 0);
int cnt = 0; LL res = 0; for (int i = 1; i <= m; i++) { if (qry[i].len > mid) { d[qry[i].a]++, d[qry[i].b]++; d[qry[i].u] -= 2; res = max(res, qry[i].len); cnt++; } } calc(1); LL sel = 0; for (int i = 1; i <= n; i++) { if (d[i] == cnt) sel = max(sel, 1LL * w[i]); }
return res - sel <= mid; }
intmain(){ scanf("%d%d", &n, &m); for (int i = 1, a, b, c; i < n; i++) { scanf("%d%d%d", &a, &b, &c); add(a, b, c), add(b, a, c); } dfs(1, 0, 0);
LL l = 0, r = 0; for (int i = 1; i <= m; i++) { int a, b, u; scanf("%d%d", &a, &b); u = lca(a, b); qry[i] = {a, b, u, up[a] + up[b] - 2 * up[u]}; r = max(r, qry[i].len); }
while (l < r) { LL mid = (l+r) >> 1; if (check(mid)) r = mid; else l = mid+1; }