1. 程式人生 > 實用技巧 >gmoj 6874. 【2020.11.19提高組模擬】ZYT的答案

gmoj 6874. 【2020.11.19提高組模擬】ZYT的答案

\(Solution\)

做法很妙。

考慮有貢獻的一條有向路徑\(u->v\),那勢必會有\(u\)以外一堆點走到\(v\)以外一堆點的時候產生了這條路徑的貢獻。

而對於\(dfn\)序則是幾段區間到幾段區間有貢獻,可以打\(+1,-1\)標記來處理,對於每個標記線上段樹上區間修改即可。

上面的是題解做法,下面的是\(dyp\)的做法

可以考慮用換根\(dp\),也是用線段樹來儲存答案,操作也是區間修改。

\(Code(rotate\ root\ dp)\)

#include <cstdio>
#include <vector>
#define N 100010
#define ll long long
#define ls (x << 1)
#define rs (x << 1 | 1)
#define mem(x, a) memset(x, a, sizeof x)
#define mpy(x, y) memcpy(x, y, sizeof y)
#define fo(x, a, b) for (int x = (a); x <= (b); x++)
#define fd(x, a, b) for (int x = (a); x >= (b); x--)
#define go(x) for (int p = tail[x], v; p; p = e[p].fr)
using namespace std;
struct pr{int v, cost;};
struct node{int v, fr;}e[N << 1];
int n, m, tail[N], cnt = 0, val[N], ans = 0, dep[N];
int dfn[N], fa[N][18], siz[N], tot = 0, t[N << 2], lazy[N << 2];
vector<pr> up[N], dn[N];

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

inline void add(int u, int v) {e[++cnt] = (node){v, tail[u]}; tail[u] = cnt;}

void dfs(int x) {
	dfn[x] = ++tot, siz[x] = 1;
	for (int i = 0; fa[fa[x][i]][i]; i++)
		fa[x][i + 1] = fa[fa[x][i]][i];
	go(x) if ((v = e[p].v) != fa[x][0]) {
		dep[v] = dep[x] + 1, fa[v][0] = x;
		dfs(v), siz[x] += siz[v];
	}
}

void update(int x, int l, int r) {
	if (l == r) {lazy[x] = 0; return;}
	t[ls] += lazy[x], lazy[ls] += lazy[x];
	t[rs] += lazy[x], lazy[rs] += lazy[x];
	lazy[x] = 0;
}

void modify(int x, int l, int r, int fl, int fr, int value) {
	if (lazy[x]) update(x, l, r);
	if (fl <= l && r <= fr) {
		t[x] += value, lazy[x] += value;
		update(x, l, r); return;
	}
	int mid = (l + r) >> 1;
	if (fl <= mid) modify(ls, l, mid, fl, fr, value);
	if (fr > mid) modify(rs, mid + 1, r, fl, fr, value);
	t[x] = max(t[ls], t[rs]);
}

void down_modify(int x, int zf) {
	int len = dn[x].size() - 1;
	fo(i, 0, len) {
		int vv = dn[x][i].v;
		modify(1, 1, n, dfn[vv], dfn[vv] + siz[vv] - 1, zf * dn[x][i].cost);
	}
}

int pa_son(int v, int u) {
	int now_ = v;
	for (int i = 0, cha = dep[v] - dep[u] - 1; cha > 0; cha >>= 1, i++)
		if (cha & 1) now_ = fa[now_][i];
	return now_;
}

void up_modify(int x, int zf) {
	int len = up[x].size() - 1;
	fo(i, 0, len) {
		int vv = up[x][i].v;
		if (dfn[vv] <= dfn[x] && dfn[x] <= dfn[vv] + siz[vv] - 1) {
			modify(1, 1, n, 1, n, zf * up[x][i].cost);
			int now_ = pa_son(x, vv);
			modify(1, 1, n, dfn[now_], dfn[now_] + siz[now_] - 1, zf * -up[x][i].cost);
		}
		else modify(1, 1, n, dfn[vv], dfn[vv] + siz[vv] - 1, zf * up[x][i].cost);
	}
}

void self_modify(int x, int v, int cz) {
	if (1 <= dfn[x] - 1) modify(1, 1, n, 1, dfn[x] - 1, cz * val[x]);
	if (dfn[x] + siz[x] <= n) modify(1, 1, n, dfn[x] + siz[x], n, cz * val[x]);
	modify(1, 1, n, dfn[v], dfn[v] + siz[v] - 1, cz * -val[x]);
}

int find(int x, int l, int r, int f) {
	if (lazy[x]) update(x, l, r);
	if (l == r) return t[x];
	int mid = (l + r) >> 1, s = 0;
	if (f <= mid) s = find(ls, l, mid, f);
	else s = find(rs, mid + 1, r, f);
	t[x] = max(t[ls], t[rs]);
	return s;
}

void for_answer(int x, int zf) {
	if (1 <= dfn[x] - 1) modify(1, 1, n, 1, dfn[x] - 1, zf * val[x]);
	if (dfn[x] + siz[x] <= n) modify(1, 1, n, dfn[x] + siz[x], n, zf * val[x]);
}

void rotate(int x) {
	
	up_modify(x, 1);
	
	for_answer(x, 1);
	
	ans = max(ans, t[1]);
	
	for_answer(x, -1);
	
	go(x) {
		if ((v = e[p].v) == fa[x][0]) continue;
		self_modify(x, v, 1);
		down_modify(v, -1);
		rotate(v);
		down_modify(v, 1);
		self_modify(x, v, -1);
	}
	
	up_modify(x, -1);
}

int main()
{
	freopen("score.in", "r", stdin);
	freopen("score.out", "w", stdout);
	n = read(), m = read();
	fo(i, 2, n) {
		int u = read(), v = read();
		add(u, v), add(v, u);
	}
	
	dfs(1);
	
	fo(i, 1, m) {
		int u = read(), v = read(), w = read();
		if (u == v) {
			modify(1, 1, n, dfn[v], dfn[v] + siz[v] - 1, w);
			val[u] += w; continue;
		}
		if (dfn[u] <= dfn[v] && dfn[v] <= dfn[u] + siz[u] - 1) {
			modify(1, 1, n, dfn[v], dfn[v] + siz[v] - 1, w);
			int now_ = v;
			for (int i = 0, cha = dep[v] - dep[u] - 1; cha > 0; cha >>= 1, i++)
				if (cha & 1) now_ = fa[now_][i];
			dn[now_].push_back((pr){v, w});
		}
		else up[u].push_back((pr){v, w});
	}
	
	rotate(1);
	
	printf("%d\n", ans);
	
	return 0;
}