Dyd's Blog

He who has a strong enough why can bear almost any how.

luoguP4069 [SDOI2016]游戏

李超上树

游戏

思路

不难发现修改是一次函数,若是一条链,就是李超的板子,对于树,考虑套一个树剖,因为每个点到根的距离 $dis[i]$ 对于一条重链是单调的,所以正确性有保证,在李超树上同时记录一下最小值(对于一次函数,就是算一下端点值)即可,时间 $O(n \log^3 n)$

代码

不知道为何,LL mn[N << 2]std::fill(LC::mn, LC::mn + (N << 2), INF) 会挂成 $95pts$ ,要开大空间(如下面的代码)才可过

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#include <bits/stdc++.h>
#define STC static
#define fi first
#define se second
#define FF std::function
using LL = long long;
using PII = std::pair<int, int>;
const int N = 1e5 + 100;
const LL INF = 123456789123456789;
int n, m, ctl = 0, bid[N];
std::vector<PII> G[N];
LL dis[N];
struct Line
{
int k;
LL b;
LL calc(int x){ return dis[bid[x]] * k + b; }
} li[N << 1];
namespace LC
{
using std::max;
using std::min;
int id[N << 2];
LL mn[N << 4];
#define mid (l + r >> 1)
#define lc (u << 1)
#define rc (u << 1 | 1)
bool judge(int a, int b, int x){ return li[a].calc(x) > li[b].calc(x); }
void upd(int u, int l, int r, int ql, int qr, int d)
{
STC FF<void(int, int, int)> up = [&](int u, int l, int r)
{
mn[u] = min(mn[u], min(li[id[u]].calc(l), li[id[u]].calc(r)));
mn[u] = min(mn[u], min(mn[lc], mn[rc]));
} ;
if (l >= ql && r <= qr)
{
if (judge(id[u], d, mid)) std::swap(id[u], d);
if (judge(id[u], d, l)) upd(lc, l, mid, ql, qr, d);
if (judge(id[u], d, r)) upd(rc, mid + 1, r, ql, qr, d);
return up(u, l, r);
}
if (ql <= mid) upd(lc, l, mid, ql, qr, d);
if (qr > mid) upd(rc, mid + 1, r, ql, qr, d);
up(u, l, r);
}
LL ask(int u, int l, int r, int ql, int qr)
{
if (l >= ql && r <= qr) return mn[u];
LL res = min(li[id[u]].calc(max(l, ql)), li[id[u]].calc(min(r, qr)));
if (ql <= mid) res = min(res, ask(lc, l, mid, ql, qr));
if (qr > mid) res = min(res, ask(rc, mid + 1, r, ql, qr));
return res;
}
#undef mid
#undef lc
#undef rc
}
namespace TCS //TreeChainSegmentation
{

int fa[N], top[N], id[N], cnt, dep[N], si[N], son[N];
void prev()
{
FF<void(int, int, int, LL)> dfs1 = [&](int x, int f, int d, LL di)
{
fa[x] = f, dep[x] = d, dis[x] = di, si[x] = 1;
for (PII e : G[x]) if (e.fi != f)
{
dfs1(e.fi, x, d + 1, di + e.se);
si[x] += si[e.fi];
if (si[e.fi] > si[son[x]]) son[x] = e.fi;
}
} ;
FF<void(int, int)> dfs2 = [&](int x, int t)
{
top[x] = t, id[x] = ++cnt, bid[cnt] = x;
if (!son[x]) return ;
dfs2(son[x], t);
for (PII e : G[x]) if (e.fi != fa[x] && e.fi != son[x]) dfs2(e.fi, e.fi);
} ;
dfs1(1, 0, 1, 0), dfs2(1, 1);
}
void change(int s, int t, int a, int b)
{
STC FF<int(int, int)> lca = [&](int x, int y)
{
while (top[x] != top[y]) dep[top[x]] > dep[top[y]] ? x = fa[top[x]] : y = fa[top[y]];
return dep[x] > dep[y] ? y : x;
} ;
STC FF<void(int, int, int)> modify = [&](int x, int y, int d)
{
while (top[x] != top[y]) LC::upd(1, 1, n, id[top[x]], id[x], d), x = fa[top[x]];
LC::upd(1, 1, n, id[y], id[x], d);
} ;
int ff = lca(s, t);
li[++ctl] = {-a, dis[s] * a + b}, modify(s, ff, ctl);
li[++ctl] = {a, (dis[s] - (dis[ff] << 1)) * a + b}, modify(t, ff, ctl);
}
LL ask(int s, int t)
{
LL res = INF;
while (top[s] != top[t])
{
if (dep[top[s]] < dep[top[t]]) std::swap(s, t);
res = std::min(res, LC::ask(1, 1, n, id[top[s]], id[s])), s = fa[top[s]];
}
if (id[s] > id[t]) std::swap(s, t);
return std::min(res, LC::ask(1, 1, n, id[s], id[t]));
}
}
int main()
{
scanf("%d %d", &n, &m);
for (int i = 1, u, v, w; i < n; ++i)
{
scanf("%d %d %d", &u, &v, &w);
G[u].push_back({v, w}), G[v].push_back({u, w});
}
TCS::prev(), li[0] = {0, INF};
std::fill(LC::mn, LC::mn + (N << 4), INF);
for (int op, s, t, a, b; m--; )
{
scanf("%d %d %d", &op, &s, &t);
if (op == 1)
{
scanf("%d %d", &a, &b);
TCS::change(s, t, a, b);
}
else printf("%lld\n", TCS::ask(s, t));
}
return 0;
}