JZOJ4479【GDOI2016模拟4.26】游戏 线段树维护多条线段的信息
来源:互联网 发布:js if undefined 编辑:程序博客网 时间:2024/05/29 17:51
题目大意
给你一颗
解题思路
很显然这道题目在每个点上只需记录一下最小的权值就可以了。而在树上的情况比较复杂,我们可以先讨论以下在序列上的情况。
对于序列,我们可以把距离抽象成
其实我们可以用线段树来维护直线的信息。
对于线段树的每个节点维护一个直线L,假设当前要往区间
对于查询操作,只需沿线段树往下走,把每个区间的L更新一下答案就可以了。
那么对于树上的情况,我们只需要把把树剖分一下,把线段分成几段,再用对序列的维护方法维护一下就可以了。
程序
//YxuanwKeith#include <cstring>#include <cstdio>#include <algorithm>using namespace std;typedef long long LL;const int MAXN = 3e5 + 5;const LL Inf = 123456789123456789;struct Node { int l, r; Node (int a, int b) {l = a, r = b;} Node () {}};struct Cross { LL a, b; Cross(LL x, LL y) {a = x, b = y;} Cross() {};};struct Tree { LL Min; bool Flag; Cross Line;} Tr[MAXN * 4];LL Dis[MAXN];Node L[MAXN], R[MAXN];int N, M, Bel[MAXN];int tot, Last[MAXN], Next[MAXN * 2], Go[MAXN * 2], Len[MAXN * 2];int time, Ord[MAXN], Size[MAXN], MSon[MAXN], Top[MAXN], Pre[MAXN], Deep[MAXN];void Link(int u, int v, int w) { Next[++ tot] = Last[u], Last[u] = tot, Go[tot] = v, Len[tot] = w;}void Basis(int Now, int Fa, LL len) { Dis[Now] = Dis[Fa] + len; Size[Now] = 1, Deep[Now] = Deep[Fa] + 1; Pre[Now] = Fa; for (int p = Last[Now]; p; p = Next[p]) { int v = Go[p]; if (v == Fa) continue; Basis(v, Now, Len[p]); Size[Now] += Size[v]; if (Size[v] > Size[MSon[Now]]) MSon[Now] = v; }}void Promote(int Now, int top) { if (!Now) return; Top[Now] = top; Ord[Now] = ++ time; Bel[time] = Now; Promote(MSon[Now], top); for (int p = Last[Now]; p; p = Next[p]) { int v = Go[p]; if (v == Pre[Now] || v == MSon[Now]) continue; Promote(v, v); }}void Build(int Now, int l, int r) { Tr[Now].Min = Inf; if (l == r) return; int Mid = (l + r) >> 1; Build(Now * 2, l, Mid), Build(Now * 2 + 1, Mid + 1, r);}void Prepare() { Basis(1, 0, 0), Promote(1, 1); Build(1, 1, N);}LL Calc(Cross Now, int Side) { return Now.a * Dis[Bel[Side]] + Now.b;}LL GetMin(Cross Now, int l, int r) { return min(Calc(Now, l), Calc(Now, r));}void Update(int Now, int l, int r) { LL Ans = Inf; if (Tr[Now].Flag) Ans = GetMin(Tr[Now].Line, l, r); if (l == r) { Tr[Now].Min = Ans; return; } Tr[Now].Min = min(Ans, min(Tr[Now * 2].Min, Tr[Now * 2 + 1].Min));}void Modify(int Now, int l, int r, int lx, int rx, Cross New) { if (r < lx || rx < l || l > r) return; int Mid = (l + r) >> 1; if (l >= lx && r <= rx) { if (!Tr[Now].Flag) { Tr[Now].Line = New; Tr[Now].Flag = 1; Update(Now, l, r); return; } Cross Good = Tr[Now].Line, Bad = New; if (Calc(New, Mid) < Calc(Good, Mid)) swap(Good, Bad); Tr[Now].Line = Good; if (l != r) { if (Calc(Bad, r) < Calc(Good, r)) Modify(Now * 2 + 1, Mid + 1, r, lx, rx, Bad); else Modify(Now * 2, l, Mid, lx, rx, Bad); } Update(Now, l, r); return; } Modify(Now * 2, l, Mid, lx, rx, New), Modify(Now * 2 + 1, Mid + 1, r, lx, rx, New); Update(Now, l, r);}void Modify(int s, int t, LL a, LL b) { int NumL = 0, NumR = 0, u = s, v = t; while (Top[u] != Top[v]) { if (Deep[Top[u]] > Deep[Top[v]]) { L[++ NumL] = Node(Ord[Top[u]], Ord[u]); u = Pre[Top[u]]; } else { R[++ NumR] = Node(Ord[Top[v]], Ord[v]); v = Pre[Top[v]]; } } int top; if (Deep[u] < Deep[v]) R[++ NumR] = Node(Ord[u], Ord[v]), top = u; else L[++ NumL] = Node(Ord[v], Ord[u]), top = v; for (int i = 1; i <= NumL; i ++) Modify(1, 1, N, L[i].l, L[i].r, Cross(-a, a * Dis[s] + b)); for (int i = NumR; i; i --) Modify(1, 1, N, R[i].l, R[i].r, Cross(a, a * (Dis[s] - 2 * Dis[top]) + b));}LL Query(int Now, int l, int r, int lx, int rx) { if (r < lx || l > rx) return Inf; if (l >= lx && r <= rx) return Tr[Now].Min; int Mid = (l + r) >> 1; LL Ans = Inf; if (Tr[Now].Flag) Ans = GetMin(Tr[Now].Line, max(l, lx), min(r, rx)); return min(Ans, min(Query(Now * 2, l, Mid, lx, rx), Query(Now * 2 + 1, Mid + 1, r, lx, rx)));}void Query(int u, int v) { LL Ans = Inf; while (Top[u] != Top[v]) { if (Deep[Top[u]] < Deep[Top[v]]) swap(u, v); Ans = min(Ans, Query(1, 1, N, Ord[Top[u]], Ord[u])); u = Pre[Top[u]]; } if (Deep[u] < Deep[v]) swap(u, v); Ans = min(Ans, Query(1, 1, N, Ord[v], Ord[u])); printf("%lld\n", Ans);}int main() { scanf("%d%d", &N, &M); for (int i = 1; i < N; i ++) { int u, v, w; scanf("%d%d%d", &u, &v, &w); Link(u, v, w), Link(v, u, w); } Prepare(); for (int i = 1; i <= M; i ++) { int Ord, s, t; scanf("%d%d%d", &Ord, &s, &t); if (Ord == 1) { LL a, b; scanf("%lld%lld", &a, &b); Modify(s, t, a, b); } else Query(s, t); }}
1 0
- JZOJ4479【GDOI2016模拟4.26】游戏 线段树维护多条线段的信息
- 【BZOJ4515】游戏,树链剖分+永久化标记线段树维护线段信息(李超线段树)
- JZOJ4417 【HNOI2016模拟4.1】神奇的字符串 线段树维护信息
- JZOJ4774 【GDOI2017模拟9.10】子串 线段树合并维护SAM的fail树信息(CF 666E类似)
- 用线段树维护树的直径
- 斐波纳契数列 线段树的维护
- 树链剖分 SPOJ375 线段树的维护
- JZOJ4686 卡牌游戏 线段树维护贪心策略
- bzoj 4515 [Sdoi2016]游戏 线段树维护凸包
- 东东的高速之旅 (线段树维护区间最小值)(模拟赛)
- 【GDOI2017模拟一试4.11】腐女的生日(线段树+维护一次函数)
- HDU-1540 Tunnel Warfare (线段树 维护端点信息)
- hdu4288(线段树维护多个sum)
- poj3468线段树维护多个数据
- 线段树区间维护upcoj
- 线段树区间维护hdu3308
- 线段树区间维护hdu3397
- 线段树区间维护cf46D
- Android - some basic control & resource operations
- python中yield深入理解
- java反射
- Android - Start new Activity & Pass value
- java 8 LocalDateTime 20 例
- JZOJ4479【GDOI2016模拟4.26】游戏 线段树维护多条线段的信息
- C++内存管理
- ueditor的使用jsp版
- Android - usage of TextWatcher
- Python 2.7.x 与 Python 3.x 的主要差异
- 今天是值得记载的一天
- Qt5的QPoint 和 QPointF
- 数据库SQL编写规范
- 我读R-CNN