P4069 [SDOI2016]游戏 [李超树,树链剖分]

Posted isaunoya

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P4069 [SDOI2016]游戏 [李超树,树链剖分]相关的知识,希望对你有一定的参考价值。

考虑到某个连续的段一定是离根的长度增加于是随便搞就行了,有点难调。

// by Isaunoya
#include<bits/stdc++.h>
#define rep(i, x, y) for(int i = x; i <= y; ++i)
#define Rep(i, x, y) for(int i = x; i >= y; --i)
#define int long long
using namespace std;
struct io {
	char buf[1 << 27 | 3], *s;
	int f;
	io() { f = 0, buf[fread(s = buf, 1, 1 << 27, stdin)] = ‘
‘; }
	io& operator >> (int&x) {
		for(x = f = 0; !isdigit(*s); ++s) f |= *s  == ‘-‘;
		while(isdigit(*s)) x = x * 10 + (*s++ ^ 48);
		return x = f ? -x : x, *this;
	}
};
struct io_out {
	char buf[1 << 27 | 3], *s = buf;
	~io_out() { fwrite(buf, 1, s - buf, stdout); }
	void write(int x) { if(x > 9) write(x / 10); *s++ = x % 10 ^ ‘0‘; }
	io_out& operator << (int x) {
		if(x < 0) x = -x, *s++ = ‘-‘;
		write(x); return *this;
	}
	io_out& operator << (char x) { *s++ = x; return *this; }
} out;
int n;
const int maxn = 4e5 + 54;
struct Edge {
	int v, nxt, w;
} e[maxn << 1];
int head[maxn], cnt = 0;
void add(int u, int v, int w) {
	e[++ cnt] = { v, head[u], w }, head[u] = cnt;
	e[++ cnt] = { u, head[v], w }, head[v] = cnt;
}
const int inf = 123456789123456789ll;
struct Line {
	int k, b;
	Line(int _k = 0, int _b = inf) { k = _k, b = _b; }
	int val(int x) { return k * x + b; }
} a[maxn << 1];
int fa[maxn], sz[maxn], dep[maxn], len[maxn], f[maxn][22], son[maxn];
void dfs(int u) {
	sz[u] = 1, dep[u] = dep[fa[u]] + 1;
	for(int i = head[u], v = e[i].v; i; v = e[i = e[i].nxt].v) 
		if(v != fa[u]) { fa[v] = u, len[v] = len[u] + e[i].w; dfs(v); sz[u] += sz[v]; if(sz[v] > sz[son[u]]) son[u] = v; }
}
int lca(int x, int y) {
	if(dep[x] < dep[y]) swap(x, y);
	for(int i = 20; ~i; --i) if(dep[f[x][i]] >= dep[y]) x = f[x][i]; if(x == y) return x;
	for(int i = 20; ~i; --i) if(f[x][i] ^ f[y][i]) { x = f[x][i], y = f[y][i]; }
	return f[x][0];
}
int top[maxn], idx = 0, dfn[maxn], rev[maxn];
void dfs(int u, int t) {
	top[u] = t, dfn[u] = ++idx; rev[dfn[u]] = u; if(son[u]) dfs(son[u], t);
	for(int i = head[u], v = e[i].v; i; v = e[i = e[i].nxt].v) if(!top[v]) dfs(v, v);
}
struct LCT {
	LCT() {}
	int id[maxn << 2], mn[maxn << 2];
	void up(int p) { mn[p] = min({mn[p], mn[p << 1], mn[p << 1 | 1]}); }
	void build(int l, int r, int p) {
		mn[p] = inf; id[p] = 0; if(l == r) { return ; }
		int mid = l + r >> 1; build(l, mid, p << 1), build(mid + 1, r, p << 1 | 1); up(p);
	}
	void upd(int ql, int qr, int l, int r, int p, int x) {
		int mid = l + r >> 1;
		if(ql <= l && r <= qr) {
			int &y = id[p]; 
			int lx = a[x].val(len[rev[l]]), ly = a[y].val(len[rev[l]]);
			int rx = a[x].val(len[rev[r]]), ry = a[y].val(len[rev[r]]);
			if(lx <= ly && rx <= ry) { y = x; mn[p] = min({mn[p], lx, rx}); return; }
			if(lx >= ly && rx >= ry) { return; }
			int midx = a[x].val(len[rev[mid]]), midy = a[y].val(len[rev[mid]]);
			if(midx <= midy) swap(x, y), swap(midx, midy), swap(lx, ly), swap(rx, ry);
			if(lx <= ly) upd(ql, qr, l, mid, p << 1, x);
			else upd(ql, qr, mid + 1, r, p << 1 | 1, x);
			mn[p] = min({mn[p], lx, rx, ly, ry}), up(p); return;
		}
		if(ql <= mid) upd(ql, qr, l, mid, p << 1, x);
		if(qr > mid) upd(ql, qr, mid + 1, r, p << 1 | 1, x);
		up(p);
	}
	int qry(int ql, int qr, int l, int r, int p) {
		if(ql <= l && r <= qr) { return mn[p]; }
		int mid = l + r >> 1, ans = inf;
		if(a[id[p]].b != inf) ans = min({ans, a[id[p]].val(len[rev[max(l, ql)]]), a[id[p]].val(len[rev[min(r, qr)]])});
		if(ql <= mid) ans = min(ans, qry(ql, qr, l, mid, p << 1));
		if(qr > mid) ans = min(ans, qry(ql, qr, mid + 1, r, p << 1 | 1)); 
		return ans;
	}
} smt;
int tot = 0;
void upd(int x, int y) {
	while(top[x] != top[y]) { smt.upd(dfn[top[x]], dfn[x], 1, n, 1, tot), x = fa[top[x]]; }
	smt.upd(dfn[y], dfn[x], 1, n, 1, tot);
}
void mdf(int s, int t, int k, int b) {
	int Lca = lca(s, t); a[++ tot] = Line(-k, k * len[s] + b); upd(s, Lca);
	a[++ tot] = Line(k, k * (len[s] - (len[Lca] << 1)) + b); upd(t, Lca);
}
int qry(int x, int y) {
	int ans = inf;
	while(top[x] != top[y]) {
		if(dep[top[x]] < dep[top[y]]) swap(x, y);
		ans = min(ans, smt.qry(dfn[top[x]], dfn[x], 1, n, 1)); x = fa[top[x]];
	}
	if(dep[x] > dep[y]) swap(x, y); ans = min(ans, smt.qry(dfn[x],dfn[y], 1, n, 1));
	return ans;
}
signed main() {
#ifdef LOCAL
	freopen("testdata.in", "r", stdin);
#endif
	io in;
	in >> n; int _; in >> _;
	rep(i, 2, n) { int x, y, z; in >> x >> y >> z, add(x, y, z); }
	dfs(1), dfs(1, 1); rep(i, 1, n) f[i][0] = fa[i]; rep(j, 1, 20) rep(i, 1, n) f[i][j] = f[f[i][j - 1]][j - 1];
	smt.build(1, n, 1);
	while(_ --) {
		int op, s, t, a, b;
		in >> op >> s >> t; if(op == 1) in >> a >> b;
		if(op == 1) { mdf(s, t, a, b); } else { out << qry(s, t) << ‘
‘; }
	}
	return 0;
}

以上是关于P4069 [SDOI2016]游戏 [李超树,树链剖分]的主要内容,如果未能解决你的问题,请参考以下文章

P4069 [SDOI2016]游戏

[SDOI2016]游戏 树剖+李超树

[SDOI2016]游戏(树链剖分,李超线段树模板)

[bzoj4515] [Sdoi2016]游戏

2021-10-09

数据结构(树链剖分,线段树):SDOI 2016 游戏