#include <iostream>
#include <algorithm>
#include <cstring>
typedef long long ll;
typedef std::pair<double, int> PDI;
const int N = 1e5, M = 2e5 + 10;
const ll INF = 123456789123456789;
int n, m, cnt;
int h[N], e[M], ne[M], idx;
int id[N], cnt1;
int dep[N], sz[N], top[N], fa[N], son[N];
ll len[N], w[M], nw[N];
inline void add(int a, int b, ll c){
ne[idx] = h[a], e[idx] = b, w[idx] = c, h[a] = idx ++;
}
struct Segment {
ll k, b;
}seg[M << 1];
struct node {
int l, r;
ll mn;
int id;
}tr[N << 2];
inline void ADD(ll k, ll b) {
seg[++ cnt] = {k, b};
}
inline int cmp(ll x, ll y) {
if(x < y) return 1;
else if(y > x) return -1;
return 0;
}
inline ll calc(int id, ll x) {
return seg[id].k * x + seg[id].b;
}
inline void pushup(int u) {
tr[u].mn = std::min(std::min(tr[u << 1].mn, tr[u].mn), tr[u << 1 | 1].mn);
}
inline void build_tree(int u, int l, int r) {
tr[u] = {l, r, INF};
if(l == r) return ;
int mid = l + r >> 1;
build_tree(u << 1, l, mid);
build_tree(u << 1 | 1, mid + 1, r);
}
inline void update(int u, int v) {
int& k = tr[u].id;
int mid = tr[u].l + tr[u].r >> 1;
tr[u].mn = std::min(std::min(tr[u].mn, calc(v, nw[tr[u].l])), calc(v, nw[tr[u].r]));
tr[u].mn = std::min(std::min(tr[u].mn, calc(k, nw[tr[u].r])), calc(k, nw[tr[u].r]));
if(cmp(calc(v, nw[mid]), calc(k, nw[mid])) == 1) std::swap(k, v);
int d1 = cmp(calc(v, nw[tr[u].l]), calc(k, nw[tr[u].l])), d2 = cmp(calc(v, nw[tr[u].r]), calc(k, nw[tr[u].r]));
if(d1 == 1) update(u << 1, v);
if(d2 == 1) update(u << 1 | 1, v);
}
inline void modify(int u, int l, int r) {
if(tr[u].l >= l && tr[u].r <= r){//定位update区间
update(u, cnt);
return ;
}
int mid = tr[u].l + tr[u].r >> 1;
if(l <= mid) modify(u << 1, l, r);
if(r > mid) modify(u << 1 | 1, l, r);
pushup(u);
}
inline ll query(int u, int l, int r) {
ll res = INF;
if(tr[u].l >= l && tr[u].r <= r) return tr[u].mn;
int mid = tr[u].l + tr[u].r >> 1;
res = std::min({res, calc(tr[u].id, nw[std::max(tr[u].l, l)]), calc(tr[u].id, nw[std::min(tr[u].r, r)])});
if (l <= mid) res = std::min(res, query(u << 1, l, r));
if (r > mid) res = std::min(res, query(u << 1 | 1, l, r));
return res;
}
//统计子树大小 并且 找出重儿子
inline void dfs1(int u, int father, int depth, ll cd){
dep[u] = depth, fa[u] = father, sz[u] = 1;
len[u] = cd;
for (int i = h[u]; ~i; i = ne[i]){
int j = e[i];
if (j == father) continue;
dfs1(j, u, depth + 1, cd + w[i]);
sz[u] += sz[j];
if (sz[son[u]] < sz[j]) son[u] = j;
}
}
//dfs序 nw标记dfs为cnt的时候对应的树上点的权值 top标记父亲是谁
inline void dfs2(int u, int t){
id[u] = ++ cnt1, top[u] = t, nw[cnt1] = len[u];
if (!son[u]) return;
dfs2(son[u], t);
for (int i = h[u]; ~i; i = ne[i]){
int j = e[i];
if (j == fa[u] || j == son[u]) continue;
dfs2(j, j);
}
}
inline int LCA(int u, int v) {
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) std::swap(u, v);
if(u == fa[top[u]]) return u;
u = fa[top[u]];
}
if (dep[u] < dep[v]) return u;
return v;
}
//传进来想要爬的两个点
inline void update_path(int u, int v) {
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) std::swap(u, v);
modify(1, id[top[u]], id[u]);
u = fa[top[u]];
}
if (dep[u] < dep[v]) std::swap(u, v);
modify(1, id[v], id[u]);
}
inline ll query_path(int u, int v){
ll mn = INF;
while (top[u] != top[v])
{
if (dep[top[u]] < dep[top[v]]) std::swap(u, v);
mn = std::min(mn, query(1, id[top[u]], id[u]));
u = fa[top[u]];
}
if (dep[u] < dep[v]) std::swap(u, v);
mn = std::min(mn, query(1, id[v], id[u]));
return mn;
}
inline void Init(){
dfs1(1, -1, 1, 0);
dfs2(1, 1);
}
inline void solve(){
memset(h, -1, sizeof h);
std::cin >> n >> m;
for(int i = 1; i < n; i ++) {
int a, b;
ll c;
std::cin >> a >> b >> c;
add(a, b, c);
add(b, a, c);
}
Init();
build_tree(1, 1, n);
seg[0] = {0, INF};
int op, u, v;
ll a, b;
while(m --) {
std::cin >> op >> u >> v;
if(op == 1){
int lca = LCA(u, v);
std::cin >> a >> b;
ll k = -a, c = b + a * len[u];
ADD(k, c);
update_path(u, lca);
k = a, c = a * (len[u] - len[lca] * 2) + b;
ADD(k, c);
update_path(lca, v);
}else{
std::cout << query_path(u, v) << '\n';
}
}
}
int main(void) {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
int _ = 1;
while(_ --)
solve();
return 0;
}
标签:std,int,线段,tr,李超,SDOI2016,calc,ll,nw
From: https://www.cnblogs.com/qdhys/p/17310948.html