P4556 [Vani有约会] 雨天的尾巴

P4556 [Vani有约会] 雨天的尾巴

虽说是模板题,但是调代码花的时间不少,记录下。

这题的重要思想就是树上差分。例如此题就是在 \(x\)\(y\) 处打上 \((z,1)\) 的标记,在 \(lca(x,y)\)\(fa(lca(x,y))\) 处打上 \((z,-1)\) 的标记。

对于一个点 \(x\) 的实际存放的救济粮就是为 \(x\) 子树内所有的点(包括 \(x\))的值域之和。这里就需要用到线段树合并了,从叶子节点向根节点合并,并计算答案。

当然值域那么大(1e5^2)就得用到动态开点了。

时间复杂度:\(O((n+m)\log n)\)

本人太弱了,空间是随便开的,不想算

核心代码:

void pushup(int p) {
	if (t[ls].mx >= t[rs].mx) t[p].mx = t[ls].mx, t[p].res = t[ls].res;
	else t[p].mx = t[rs].mx, t[p].res = t[rs].res;
}

void modify(int &p, int l, int r, int k, int x) {
	if (!p) p = ++cnt;
	if (l == r) {
		t[p].mx += x, t[p].res = l;
		if (!t[p].mx) t[p].res = 0;
		return;
	}
	int mid = l+r>>1;
	if (k <= mid) modify(ls, l, mid, k, x);
	else modify(rs, mid+1, r, k, x);
	pushup(p);
}

int merge(int p, int q, int l, int r) {
	if (!p || !q) return p+q;
	if (l == r) {
		t[p].mx += t[q].mx, t[p].res = l;
		if (!t[p].mx) t[p].res = 0;
		return p;
	}
	int mid = l+r>>1;
	t[p].l = merge(t[p].l, t[q].l, l, mid);
	t[p].r = merge(t[p].r, t[q].r, mid+1, r);
	pushup(p);
	return p;
}

void dfs2(int x, int fa) {
	for (int i = head[x]; i; i = e[i].next) if (e[i].to != fa) {
		dfs2(e[i].to, x);
		rt[x] = merge(rt[x], rt[e[i].to], 1, 1e5);
	}
	ans[x] = t[rt[x]].res;
}
posted @ 2023-12-09 11:01  123wwm  阅读(41)  评论(0)    收藏  举报