P3976 [TJOI2015] 旅游

P3976 [TJOI2015] 旅游

终于过这题了/ll

题意是让我们将路径上的点捋直然后求编号小的减去编号大的最大值,然后有区间修改。

考虑树链剖分,将问题转化为序列上的问题,对于一段区间 \([l,r]\),我们要求 \([l,r]\) 之间编号小的减去编号大的最大值,我们可以把问题分为 \([l,mid]\)\([mid+1,r]\) 两部分,假设我们已经求出了 \([l,mid]\)\([mid+1,r]\) 的答案。

对于可能为答案的点对 \((i,j)\),有三种情况:

  1. \(l\le i<j\le mid\),这已经在 \([l,mid]\) 中求出了。

  2. \(mid+1\le i<j\le r\),这己经在 \([mid+1, r]\) 中求出了。

  3. \(i\le mid<j\)

我们要求的即为情况 \(3\),此时的答案仅为 \([l,mid]\) 中的最大值减去 \([mid+1, r]\) 中的最小值。

所以 \([l,r]\) 的答案为以上 \(3\) 情况取 \(\min\) 即可。

这个过程可以用线段树来维护,只需要维护区间最大值,区间最小值,编号小的减去编号大的最大值以及编号大的减去编号小的最大值(维护这两个的原因是原问题是从 \(x\)\(y\),有两种情况)。

那么这个问题就解决了,代码不太好写。

#include <bits/stdc++.h>
#define ls p<<1
#define rs p<<1|1
#define fi first
#define se second
#define pb push_back
#define mk make_pair
#define ll long long
#define space putchar(' ')
#define enter putchar('\n')
using namespace std;

inline int read() {
	int x = 0, f = 1;
	char c = getchar();
	while (c < '0' || c > '9') f = c == '-' ? -1 : f, c = getchar();
	while (c >= '0' && c <= '9') x = (x<<3)+(x<<1)+(c^48), c = getchar();
	return x*f;
}

inline void write(int x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x/10);
	putchar('0'+x%10);
}

const int N = 5e4+5, inf = 1e9;
struct seg {
	int mx, mn, lmx, rmx, add;
	seg(int mx = 0, int mn = 0, int lmx = 0, int rmx = 0, int add = 0):mx(mx), mn(mn), lmx(lmx), rmx(rmx), add(add) {}
} t[N<<2];
int n, m, idx, a[N], d[N], fa[N], id[N], to[N], siz[N], son[N], top[N];
vector <int> E[N];

void dfs1(int x, int f) {
	d[x] = d[f]+1, fa[x] = f, siz[x] = 1; int mx = 0;
	for (int y:E[x]) if (y != f) {
		dfs1(y, x);
		siz[x] += siz[y];
		if (siz[y] > mx) son[x] = y, mx = siz[y];
	}
}

void dfs2(int x, int topf) {
	id[x] = ++idx, to[idx] = x, top[x] = topf;
	if (!son[x]) return;
	dfs2(son[x], topf);
	for (int y:E[x]) if (y != fa[x] && y != son[x]) dfs2(y, y);
}

void pushup(int p) {
	t[p].mx = max(t[ls].mx, t[rs].mx);
	t[p].mn = min(t[ls].mn, t[rs].mn);
	t[p].lmx = max(max(t[ls].lmx, t[rs].lmx), t[ls].mx-t[rs].mn);
	t[p].rmx = max(max(t[ls].rmx, t[rs].rmx), t[rs].mx-t[ls].mn);
}

void pushdown(int p) {
	t[ls].mx += t[p].add;
	t[ls].mn += t[p].add;
	t[ls].add += t[p].add;
	t[rs].mx += t[p].add;
	t[rs].mn += t[p].add;
	t[rs].add += t[p].add;
	t[p].add = 0;
}

void build(int p, int l, int r) {
	if (l == r) return (void)(t[p] = seg(a[to[l]], a[to[l]]));
	int mid = l+r>>1;
	build(ls, l, mid), build(rs, mid+1, r);
	pushup(p);
}

void upd(int p, int l, int r, int ql, int qr, int x) {
	if (qr < l || r < ql) return;
	if (ql <= l && r <= qr) {
		t[p].mx += x;
		t[p].mn += x;
		t[p].add += x;
		return;
	}
	pushdown(p); int mid = l+r>>1;
	upd(ls, l, mid, ql, qr, x), upd(rs, mid+1, r, ql, qr, x);
	pushup(p);
}

seg que(int p, int l, int r, int ql, int qr) {
	if (ql <= l && r <= qr) return t[p];
	pushdown(p); int mid = l+r>>1;
	if (qr <= mid) return que(ls, l, mid, ql, qr);
	if (mid < ql) return que(rs, mid+1, r, ql, qr);
	seg x = que(ls, l, mid, ql, qr), y = que(rs, mid+1, r, ql, qr), res;
	res.mx = max(x.mx, y.mx);
	res.mn = min(x.mn, y.mn);
	res.lmx = max(max(x.lmx, y.lmx), x.mx-y.mn);
	res.rmx = max(max(x.rmx, y.rmx), y.mx-x.mn);
	return res;
}

void modify(int x, int y, int k) {
	while (top[x] != top[y]) {
		if (d[top[x]] < d[top[y]]) swap(x, y);
		upd(1, 1, n, id[top[x]], id[x], k);
		x = fa[top[x]];
	}
	if (d[x] > d[y]) swap(x, y);
	upd(1, 1, n, id[x], id[y], k);
}

int solve(int x, int y) {
	seg l(-inf, inf), r(-inf, inf); int rev = 0;
	while (top[x] != top[y]) {
		if (d[top[x]] < d[top[y]]) swap(x, y), swap(l, r), rev ^= 1;
		seg k = que(1, 1, n, id[top[x]], id[x]), res;
		res.mx = max(l.mx, k.mx);
		res.mn = min(l.mn, k.mn);
		res.lmx = max(max(l.lmx, k.lmx), k.mx-l.mn);
		res.rmx = max(max(l.rmx, k.rmx), l.mx-k.mn);
		l = res;
		x = fa[top[x]];
	}
	if (d[x] > d[y]) swap(x, y), swap(l, r), rev ^= 1;
	seg k = que(1, 1, n, id[x], id[y]), res;
	res.mx = max(r.mx, k.mx);
	res.mn = min(r.mn, k.mn);
	res.lmx = max(max(r.lmx, k.lmx), k.mx-r.mn);
	res.rmx = max(max(r.rmx, k.rmx), r.mx-k.mn);
	r = res;
	if (rev) swap(l, r);
	return max(max(l.lmx, r.rmx), r.mx-l.mn);
}

int main() {
	n = read();
	for (int i = 1; i <= n; ++i) a[i] = read();
	for (int i = 1; i < n; ++i) {
		int x = read(), y = read();
		E[x].pb(y), E[y].pb(x);
	}
	dfs1(1, 0), dfs2(1, 1), build(1, 1, n);
	m = read();
	while (m--) {
		int x = read(), y = read(), k = read();
		write(solve(x, y)), enter;
		modify(x, y, k);
	}
	return 0;
}
posted @ 2024-01-24 16:47  123wwm  阅读(14)  评论(0)    收藏  举报