4515: [Sdoi2016]游戏
分析:
树链剖分 + 超哥线段树。注意细节。
代码:
#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<iostream> #include<cctype> #include<set> #include<vector> #include<queue> #include<map> #define Root 1, n, 1 #define lson l, mid, rt << 1 #define rson mid + 1, r, rt << 1 | 1 using namespace std; typedef long long LL; inline int read() { int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; } const int N = 100005; const LL INF = 123456789123456789ll; struct Edge{ int to, nxt, w; } e[N << 1]; int head[N], dep[N], siz[N], fa[N], son[N], dfn[N], bel[N], n, En, Index; LL dis[N]; struct Line{ LL k, b; Line() { k = 0, b = INF; } Line(LL _k,LL _b) { k = _k, b = _b; } LL f(LL x) { return x * k + b; } }; inline void add_edge(int u,int v,int w) { ++En; e[En].to = v, e[En].w = w, e[En].nxt = head[u]; head[u] = En; ++En; e[En].to = u, e[En].w = w, e[En].nxt = head[v]; head[v] = En; } struct SegmentTree{ LL ans[N << 2], A[N]; Line T[N << 2]; void init() { for (int i = 0; i <= (N << 2); ++i) ans[i] = INF; } inline void pushup(int rt) { ans[rt] = min(ans[rt], min(ans[rt << 1], ans[rt << 1 | 1])); } void Cover(int l,int r,int rt,Line v) { int mid = (l + r) >> 1; if (v.f(A[mid]) < T[rt].f(A[mid])) ans[rt] = min(ans[rt], min(v.f(A[l]), v.f(A[r]))), swap(v, T[rt]); // A[l]!!! if (l == r) return ; if (v.f(A[l]) > T[rt].f(A[l]) && v.f(A[r]) > T[rt].f(A[r])) return ; if (v.k > T[rt].k) Cover(lson, v); else Cover(rson, v); pushup(rt); } void update(int l,int r,int rt,int L,int R,Line v) { if (L <= l && r <= R) { Cover(l, r, rt, v); return ; } int mid = (l + r) >> 1; if (L <= mid) update(lson, L, R, v); if (R > mid) update(rson, L, R, v); pushup(rt); } LL query(int l,int r,int rt,int L,int R) { if (L <= l && r <= R) return ans[rt]; // L <= r !!! int mid = (l + r) >> 1; LL res = min(T[rt].f(A[max(l, L)]), T[rt].f(A[min(r, R)])); if (L <= mid) res = min(res, query(lson, L, R)); if (R > mid) res = min(res, query(rson, L, R)); return res; } }T; void dfs1(int u) { dep[u] = dep[fa[u]] + 1; siz[u] = 1; for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if (v == fa[u]) continue; fa[v] = u; dis[v] = dis[u] + e[i].w; dfs1(v); siz[u] += siz[v]; if (!son[u] || siz[son[u]] < siz[v]) son[u] = v; } } void dfs2(int u,int top) { bel[u] = top; dfn[u] = ++Index; T.A[Index] = dis[u]; if (!son[u]) return ; dfs2(son[u], top); for (int i = head[u]; i; i = e[i].nxt) if (e[i].to != fa[u] && e[i].to != son[u]) dfs2(e[i].to, e[i].to); } int LCA(int u,int v) { while (bel[u] != bel[v]) dep[bel[u]] > dep[bel[v]] ? u = fa[bel[u]] : v = fa[bel[v]]; return dep[u] < dep[v] ? u : v; } void Change(int u,int w,Line x) { while (bel[u] != bel[w]) T.update(Root, dfn[bel[u]], dfn[u], x), u = fa[bel[u]]; T.update(Root, dfn[w], dfn[u], x); } void Query() { int u = read(), v = read(); LL res = INF; while (bel[u] != bel[v]) { if (dep[bel[u]] < dep[bel[v]]) swap(u, v); res = min(res, T.query(Root, dfn[bel[u]], dfn[u])); u = fa[bel[u]]; } if (dep[u] < dep[v]) swap(u, v); res = min(res, T.query(Root, dfn[v], dfn[u])); printf("%lld\n", res); } int main() { n = read();int m = read(); for (int i = 1; i < n; ++i) { int u = read(), v = read(), w = read(); add_edge(u, v, w); } dfs1(1); dfs2(1, 1); T.init(); while (m --) { int opt = read(); if (opt == 1) { int u = read(), v = read(), w = LCA(u, v);LL a = read(), b = read(); Change(u, w, Line(-a, b + dis[u] * a)); Change(v, w, Line(a, b + a * (dis[u] - (dis[w] << 1)))); } else Query(); } return 0; }