SP6779 GSS7 - Can you answer these queries VII

Keywords: C++ Algorithm data structure ICPC

Title Link: SP6779 GSS7 - Can you answer these queries VII

General meaning

Given a tree with n n A tree with n nodes, each node has a weight w i ( ∣ w i ∣ ≤ 10000 ) w_i(|w_i| \le 10000) Wi (∣ wi ∣ ≤ 10000). Yes m m m operations:

1 a b query ( a , b ) (a, b) (a,b) the largest continuous sub segment on the path and

2 a b c ( a , b ) (a, b) (a,b) all point weights on the path are modified to c c c.

Problem solving ideas

Tree chain subdivision

We consider that if this is not a tree problem, but a sequence operation, then this problem is a very classic problem of maintaining the maximum sub segment sum of line segment tree

Considering the addition of tree operations, the difficulty is how to maintain the interval information between tree chains

We consider ( a , b ) (a, b) (a,b) not on the same chain: we use l a s t last Last represents the information of the last query. The query information of the current interval is recorded as n o w now now, so every time we merge interval information, we n o w now now as the left interval, l a s t last last is merged as a right interval
Since the point of each upward jump is uncertain (may be a a a. Or it could be b b b) So we need to use them separately l a , l b la, lb la,lb to maintain l a s t last last interval information

in consideration of ( a , b ) (a, b) (a,b) now on the same chain: we promise d e p a < d e p b dep_a < dep_b depa < DEPB, then the last information merging should be to n o w now now as the left interval, l b lb lb can be merged as the right interval l a la After the la chain is turned over, put n o w now now merge into l a la la, at this time l a la la as the left interval, n o w now now as the right interval)
Finally, we need to l a , l b la, lb The information of La and LB chains is merged. We found that we need to flip one chain before merging l a la la, so in the end l a la la as the left interval, l b lb lb is merged as the right interval)

If you don't understand the above, I recommend you to draw a picture and see it

When interval merging is involved in the tree chain, you will find that the interval information on the tree chain is "directional"

AC code

#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
typedef long long ll;
const int N = 1E5 + 10, INF = 0x3f3f3f3f;
int w[N]; //The weight of each vertex in a given tree
vector<int> edge[N]; //The edge between points on a tree

int p[N], dep[N], sz[N], son[N];
// Parent node depth node size
void dfs1(int x = 1, int fa = 0) { // x = tree root node
	p[x] = fa, dep[x] = dep[fa] + 1, sz[x] = 1; // son[x] = 0;
	for (auto& to : edge[x]) {
		if (to == fa) continue;
		dfs1(to, x);
		sz[x] += sz[to];		// In particular, if edge weight - > point weight, w[to] = edge weight shall be recorded
		if (sz[to] > sz[son[x]]) son[x] = to; //Renew your son
	}
}
int id[N], nw[N], top[N], ind;
//  New number new value: the number currently used at the top of the chain
void dfs2(int x = 1, int tp = 1) { // x = tree root node, tp = tree root node
	id[x] = ++ind, nw[ind] = w[x], top[x] = tp;

	if (!son[x]) return; //leaf node 
	dfs2(son[x], tp); //First, my son

	for (auto& to : edge[x]) {
		if (to == p[x] or to == son[x]) continue;
		dfs2(to, to);
	}
}


struct node {
	int l, r;
	int fmax, lmax, rmax, sum;
	int lazy;
}t[N << 2];
void pushdown(node& op, int lazy) {
	const int len = op.r - op.l + 1;
	if (lazy > 0) op.fmax = op.lmax = op.rmax = len * lazy;
	else op.fmax = op.lmax = op.rmax = lazy;
	op.sum = len * lazy;
	op.lazy = lazy;
}
void pushdown(int x) {
	if (t[x].lazy == INF) return;
	pushdown(t[x << 1], t[x].lazy), pushdown(t[x << 1 | 1], t[x].lazy);
	t[x].lazy = INF;
}

node merge(const node& l, const node& r) {
	node res;
	res.fmax = max({ l.fmax, r.fmax, l.rmax + r.lmax });
	res.lmax = max(l.lmax, l.sum + r.lmax);
	res.rmax = max(r.rmax, r.sum + l.rmax);
	res.sum = l.sum + r.sum;
	return res;
}
void pushup(int x) { t[x] = merge(t[x << 1], t[x << 1 | 1]); }

void build(int l, int r, int x = 1) {
	t[x] = { l, r, nw[l], nw[l], nw[l], nw[l], INF };
	if (l == r) return;
	int mid = l + r >> 1;
	build(l, mid, x << 1), build(mid + 1, r, x << 1 | 1);
	pushup(x);
}

void modify(int l, int r, int c, int x = 1) {
	if (l <= t[x].l and r >= t[x].r) {
		pushdown(t[x], c);
		return;
	}
	pushdown(x);
	int mid = t[x].l + t[x].r >> 1;
	if (l <= mid) modify(l, r, c, x << 1);
	if (r > mid) modify(l, r, c, x << 1 | 1);
	pushup(x);
}

node ask(int l, int r, int x = 1) {
	if (l <= t[x].l and r >= t[x].r) return t[x];
	pushdown(x);
	int mid = t[x].l + t[x].r >> 1;
	if (r <= mid) return ask(l, r, x << 1);
	if (l > mid) return ask(l, r, x << 1 | 1);
	node left = ask(l, r, x << 1), right = ask(l, r, x << 1 | 1);
	return merge(left, right);
}


void modify_route(int a, int b, int c) {
	while (top[a] != top[b]) {
		if (dep[top[a]] < dep[top[b]]) swap(a, b);
		modify(id[top[a]], id[a], c);
		a = p[top[a]];
	}
	if (id[a] > id[b]) swap(a, b);
	modify(id[a], id[b], c);
}

int ask_route(int a, int b) {
	node la = { 0, 0, 0, 0, 0, 0, 0 }, lb = { 0, 0, 0, 0, 0, 0, 0 };
	while (top[a] != top[b]) {
		if (dep[top[a]] < dep[top[b]]) swap(a, b), swap(la, lb);
		la = merge(ask(id[top[a]], id[a]), la);
		a = p[top[a]];
	}

	if (dep[a] > dep[b]) swap(a, b), swap(la, lb);
	lb = merge(ask(id[a], id[b]), lb);
	swap(la.lmax, la.rmax);
	return merge(la, lb).fmax;
}

int main()
{
	int n; cin >> n;
	rep(i, n) scanf("%d", &w[i]);
	rep(i, n - 1) {
		int a, b; scanf("%d %d", &a, &b);
		edge[a].push_back(b), edge[b].push_back(a);
	}

	dfs1(), dfs2();
	build(1, n);

	int m; cin >> m;
	rep(i, m) {
		int tp, a, b; scanf("%d %d %d", &tp, &a, &b);
		if (tp == 1) printf("%d\n", ask_route(a, b));
		else {
			int c; scanf("%d", &c);
			modify_route(a, b, c);
		}
	}

	return 0;
}

END

Posted by Ghost_81st on Sat, 06 Nov 2021 13:27:50 -0700