SDOI2016 游戏

Day 4。

\(\text{lca}(u,v)=w\)\(s_u\)\(u\) 到根的距离(随便指定一个根),考虑 \(u\to w\to v\) 的路径修改:

  • \(x\in \{u\to w\}\)\(n_x\gets a(s_u-s_x)+b=-a\cdot s_x+(b+a\cdot s_u)\)
  • \(x\in \{w\to v\}\)\(n_x\gets a(s_u+s_x-2s_w)+b=a\cdot s_x+(a(s_u-2s_w)+b)\)

考虑树链剖分,将修改拆分到 \(O(\log n)\) 条重链中。由于重链中 \(\text{id}\) 连续,这是关于 \(\text{id}(u)\) 的一次函数形式。李超线段树维护区间线段 \(\min\),在区间中插入线段即可。

李超树区间插入(非全局)是 \(O(\log^2n)\) 的(分成 \(O(\log n)\) 个区间后分别再在每个区间中插入),所以复杂度是 \(O(n\log^3n)\) 的。不知道为啥能过。

// Problem: #2032. 「SDOI2016」游戏
// Contest: LibreOJ
// URL: https://loj.ac/p/2032
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define int long long
using namespace std;

namespace vbzIO {
    char ibuf[(1 << 20) + 1], *iS, *iT;
    #if ONLINE_JUDGE
    #define gh() (iS == iT ? iT = (iS = ibuf) + fread(ibuf, 1, (1 << 20) + 1, stdin), (iS == iT ? EOF : *iS++) : *iS++)
    #else
    #define gh() getchar()
    #endif
    #define mt make_tuple
    #define mp make_pair
    #define fi first
    #define se second
    #define pc putchar
    #define pb emplace_back
    #define ins insert
    #define era erase
    typedef tuple<int, int, int> tu3;
    typedef pair<int, int> pi;
    inline int rd() {
        char ch = gh();
        int x = 0;
        bool t = 0;
        while (ch < '0' || ch > '9') t |= ch == '-', ch = gh();
        while (ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + (ch ^ 48), ch = gh();
        return t ? ~(x - 1) : x;
    }
    inline void wr(int x) {
        if (x < 0) x = ~(x - 1), putchar('-');
        if (x > 9) wr(x / 10);
        putchar(x % 10 + '0');
    }
}
using namespace vbzIO;

const int N = 5e5 + 500;
const int inf = 123456789123456789;

int n, m, dfc, s[N];
int fa[N], sz[N], son[N], dep[N], top[N], id[N], pid[N], tr[N << 2], mn[N << 2];
vector<pi> g[N], p;

#define ls x << 1
#define rs x << 1 | 1
#define mid ((l + r) >> 1)

int cmp(int x, int y) { return (x == y ? 0 : (x > y ? 1 : -1)); }
int gety(int id, int x) { return p[id].fi * s[pid[x]] + p[id].se; }
void push(int l, int r, int s, int x) {
    int &t = tr[x];
    mn[x] = min(mn[x], min(gety(s, l), gety(s, r)));
    if (cmp(gety(s, mid), gety(t, mid)) == -1) swap(s, t);
    int fl = cmp(gety(s, l), gety(t, l)), fr = cmp(gety(s, r), gety(t, r));
    if (fl == -1 || (!fl && s < t)) push(l, mid, s, ls);
    if (fr == -1 || (!fr && s < t)) push(mid + 1, r, s, rs);
	mn[x] = min(min(mn[ls], mn[rs]), mn[x]);
}

void upd(int l, int r, int s, int t, int id, int x) {
	if (s <= l && r <= t) return push(l, r, id, x);
	if (s <= mid) upd(l, mid, s, t, id, ls);
	if (t > mid) upd(mid + 1, r, s, t, id, rs);
	mn[x] = min(min(mn[ls], mn[rs]), mn[x]);
}

int qry(int l, int r, int s, int t, int x) {
	if (s <= l && r <= t) return mn[x];
	int res = min(gety(tr[x], max(l, s)), gety(tr[x], min(r, t)));
	if (s <= mid) res = min(res, qry(l, mid, s, t, ls));
	if (t > mid) res = min(res, qry(mid + 1, r, s, t, rs));
	return res;
}

void dfs1(int u, int fat) {
	fa[u] = fat, dep[u] = dep[fat] + 1, sz[u] = 1;
	for (pi p : g[u]) {
		int v = p.fi, w = p.se;
		if (v == fat) continue;
		s[v] = s[u] + w, dfs1(v, u), sz[u] += sz[v];
		if (sz[v] > sz[son[u]]) son[u] = v;
	}
}

void dfs2(int u, int pre) {
	top[u] = pre, pid[id[u] = ++dfc] = u;
	if (son[u]) dfs2(son[u], pre);
	for (pi p : g[u]) {
		int v = p.fi;
		if (v == fa[u] || v == son[u]) continue;
		dfs2(v, v);
	}
}

int lca(int u, int v) {
	while (top[u] != top[v]) {
		if (dep[top[u]] < dep[top[v]]) swap(u, v);
		u = fa[top[u]];
	}
	return dep[u] < dep[v] ? u : v;
}

void upd(int u, int v, int i) {
	while (top[u] != top[v]) {
		if (dep[top[u]] < dep[top[v]]) swap(u, v);
		upd(1, n, id[top[u]], id[u], i, 1), u = fa[top[u]];
	}
	if (dep[u] > dep[v]) swap(u, v);
	upd(1, n, id[u], id[v], i, 1);
}

int qry(int u, int v) {
	int res = inf;
	while (top[u] != top[v]) {
		if (dep[top[u]] < dep[top[v]]) swap(u, v);
		res = min(res, qry(1, n, id[top[u]], id[u], 1)), u = fa[top[u]];
	}
	if (dep[u] > dep[v]) swap(u, v);
	return min(res, qry(1, n, id[u], id[v], 1));
}

signed main() {
	n = rd(), m = rd();
	for (int i = 1, u, v, w; i <= n - 1; i++) 
		u = rd(), v = rd(), w = rd(), g[u].pb(mp(v, w)), g[v].pb(mp(u, w));
    p.pb(mp(0, inf));
    dfs1(1, 0), dfs2(1, 1);
    for (int i = 1; i < N << 2; i++) mn[i] = inf;
    while (m--) {
    	int op = rd(), u = rd(), v = rd();
    	if (op == 1) {
    		int a = rd(), b = rd(), lc = lca(u, v);
    		p.pb(mp(-a, b + a * s[u])), upd(u, lc, p.size() - 1);
    		p.pb(mp(a, b - 2 * a * s[lc] + a * s[u])), upd(lc, v, p.size() - 1);
    	} else wr(qry(u, v)), pc('\n');
    }
    return 0;
}
posted @ 2023-09-08 07:28  Ender_32k  阅读(7)  评论(0编辑  收藏  举报