【BZOJ 3242】【UOJ #126】【CodeVS 3047】【NOI 2013】快餐店
http://www.lydsy.com/JudgeOnline/problem.php?id=3242
http://codevs.cn/problem/3047/
因为存在一条边,答案所在的点走向左右的城的最短路都不会经过这条边。
所以枚举这条边,剩下的用线段树维护。
线段树初始化搞了好久,忘了在外向树上做dp,树形dp时记录也错了,总之调了一天,吃枣药丸啊QwQ
时间复杂度$O(nlogn)$,听说有$O(n)$的单调队列做法,留一个坑以后再看。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const int N = 100003; int in() { int k = 0, fh = 1; char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) if (c == '-') fh = -1; for(; c >= '0' && c <= '9'; c = getchar()) k = (k << 3) + (k << 1) + c - '0'; return k * fh; } struct SegmentTree { int L, R, n, maid[N << 2]; ll ma[N << 2], ma_sc[N << 2], lazy[N << 2], key; void pushdown(int rt, int l, int r) { if (lazy[rt]) { ma[rt << 1] += lazy[rt]; ma[rt << 1 | 1] += lazy[rt]; if (l != r) { ma_sc[rt << 1] += lazy[rt]; ma_sc[rt << 1 | 1] += lazy[rt]; } lazy[rt << 1] += lazy[rt]; lazy[rt << 1 | 1] += lazy[rt]; lazy[rt] = 0; } } void pushup(int rt) { if (ma[rt << 1] > ma[rt << 1 | 1]) ma[rt] = ma[rt << 1], maid[rt] = maid[rt << 1]; else ma[rt] = ma[rt << 1 | 1], maid[rt] = maid[rt << 1 | 1]; if (ma[rt << 1] > ma[rt << 1 | 1]) ma_sc[rt] = max(ma[rt << 1 | 1], ma_sc[rt << 1]); else ma_sc[rt] = max(ma[rt << 1], ma_sc[rt << 1 | 1]); } void mkmaid(int rt, int l, int r, ll *s) { lazy[rt] = 0; if (l == r) { maid[rt] = l; ma[rt] = s[l]; ma_sc[rt] = -10000000000000000ll; return; } int mid = (l + r) >> 1; mkmaid(rt << 1, l, mid, s); mkmaid(rt << 1 | 1, mid + 1, r, s); pushup(rt); } void init(int num, ll *s) { n = num; mkmaid(1, 1, n, s); } void update(int rt, int l, int r) { if (L <= l && r <= R) { lazy[rt] += key; ma[rt] += key; if (l != r) ma_sc[rt] += key; return; } int mid = (l + r) >> 1; pushdown(rt, l, r); if (L <= mid) update(rt << 1, l, mid); if (R > mid) update(rt << 1 | 1, mid + 1, r); pushup(rt); } void cover(int l, int r, ll num) { L = l; R = r; key = num; update(1, 1, n); } } T1, T2; struct node { int nxt, to, w; } E[N << 1]; bool vis[N]; ll g[N], sum1[N], sum2[N], Treefr[N], Treesc[N]; int n, cnt = 0, point[N], fa[N], fadis[N], mark = 0, markf; int cir[N], cirnum, cirdis[N], lala; void ins(int u, int v, int l) {E[++cnt] = (node) {point[u], v, l}; point[u] = cnt;} void dfs(int x) { vis[x] = true; for(int i = point[x]; i; i = E[i].nxt) if (E[i].to != fa[x]) { if (vis[E[i].to]) { mark = x; markf = E[i].to; lala = E[i].w; return; } fa[E[i].to] = x; fadis[E[i].to] = E[i].w; dfs(E[i].to); if (mark) return; } } ll ans2 = 0; ll dfs2(int x) { ll ret = 0; vis[x] = true; for(int i = point[x]; i; i = E[i].nxt) if (!vis[E[i].to]) { ret = max(ret, dfs2(E[i].to) + E[i].w); if (Treefr[E[i].to] + E[i].w >= Treefr[x]) { Treesc[x] = Treefr[x]; Treefr[x] = Treefr[E[i].to] + E[i].w; } else if (Treefr[E[i].to] + E[i].w > Treesc[x]) Treesc[x] = Treefr[E[i].to] + E[i].w; } ans2 = max(ans2, Treefr[x] + Treesc[x]); return ret; } ll Query() { if (T1.maid[1] == T2.maid[1]) return max(T1.ma[1] + T2.ma_sc[1], T1.ma_sc[1] + T2.ma[1]); else return T1.ma[1] + T2.ma[1]; } int main() { n = in(); int u, v, l; for(int i = 1; i <= n; ++i) { u = in(); v = in(); l = in(); ins(u, v, l); ins(v, u, l); } fa[1] = 0; dfs(1); cir[1] = markf; cir[2] = mark; cirdis[1] = lala; cirnum = 2; memset(vis, 0, sizeof(bool) * (n + 1)); vis[mark] = true; while (mark != markf) { cirdis[cirnum] = fadis[mark]; mark = fa[mark]; vis[mark] = true; cir[++cirnum] = mark; } cirdis[cirnum] = cirdis[1]; cirdis[0] = cirdis[cirnum - 1]; for(int i = 1; i < cirnum; ++i) g[i] = dfs2(cir[i]); ll ret = 0, ans; for(int i = 1; i < cirnum; ++i) { sum1[i] = g[i] + ret; sum2[i] = g[i] - ret; ret += cirdis[i]; } T1.init(cirnum - 1, sum1); T2.init(cirnum - 1, sum2); ans = Query(); for(int i = 2; i < cirnum; ++i) { T1.cover(i - 1, i - 1, ret); T2.cover(i - 1, i - 1, -ret); T1.cover(1, cirnum - 1, -cirdis[i - 1]); T2.cover(1, cirnum - 1, cirdis[i - 1]); ans = min(ans, Query()); } ans = max(ans, ans2); printf("%.1lf\n", 1.0 * ans / 2); return 0; }
NOI 2017 Bless All