[Vani有约会]雨天的尾巴 - 线段树合并

题目描述

首先村落里的一共有 \(n\) 座房屋,并形成一个树状结构。然后救济粮分 \(m\) 次发放,每次选择两个房屋 \((x,~y)\),然后对于 \(x\) 到 \(y\)的路径上(含 \(x\) 和 \(y\))每座房子里发放一袋 \(z\) 类型的救济粮。
然后深绘里想知道,当所有的救济粮发放完毕后,每座房子里存放的最多的是哪种救济粮。

思路

对每个点开一颗权值线段树,维护每个颜色出现的次数和出现最多的颜色,路径修改时差分,对权值线段树上相应位置修改,最后向上合并线段树
每个点最多开 \(\log n\) 个点,每次四个修改,数组大小开 \(4n\log n\)

#include <vector>
#include <cstdio>
using namespace std;
const int maxn = 1e5 + 10;
const int N = 2e6 + 10;
int n,m,cnt,fa[maxn],rt[maxn],ans[maxn],dep[maxn],siz[maxn],son[maxn],top[maxn],col[N<<2],mxv[N<<2],lson[N<<2],rson[N<<2];
vector<int> edge[maxn];
inline void init(int now,int f){
	dep[now] = dep[f]+1;
	siz[now] = 1;
	fa[now] = f;
	for (size_t i = 0;i < edge[now].size();i++) {
		int to = edge[now][i];
		if (to ^ f) {
			init(to,now);
			siz[now] += siz[to];
			if (siz[son[now]] < siz[to]) son[now] = to;
		}
	}
}
inline void dfs(int now,int sum) {
	top[now] = sum;
	if (son[now]) dfs(son[now],sum);
	for (size_t i = 0;i < edge[now].size();i++) {
		int to = edge[now][i];
		if (to ^ son[now] && to ^ fa[now]) dfs(to,to);
	}
}
inline int lca(int u,int v) {
	for (;top[u] ^ top[v];u = fa[top[u]])
		if (dep[top[u]] < dep[top[v]]) swap(u,v);
	return dep[u] < dep[v] ? u : v;
}
inline void pushup(int root) {
	mxv[root] = max(mxv[lson[root]],mxv[rson[root]]);
	col[root] = mxv[lson[root]] >= mxv[rson[root]] ? col[lson[root]] : col[rson[root]];
}
bool flag = false;
inline void update(int l,int r,int& root,int x,int v) {
	if (l > x || r < x) return;
	if (!root) root = ++cnt;
	if (l == r) {
		mxv[root] += v;
		col[root] = x;
		return;
	}
	int mid = l+r>>1;
	update(l,mid,lson[root],x,v);
	update(mid+1,r,rson[root],x,v);
	pushup(root);
}
inline void merge(int l,int r,int &x,int y) {
	if (!x || !y) return x += y,void();
	if (l == r) {
		mxv[x] += mxv[y];
		col[x] = l;
		return;
	}
	int mid = l+r>>1;
	merge(l,mid,lson[x],lson[y]);
	merge(mid+1,r,rson[x],rson[y]);
	pushup(x);
}
inline void solve(int now) {
	for (size_t i = 0;i < edge[now].size();i++) {
		int to = edge[now][i];
		if (to ^ fa[now]) {
			solve(to);
			merge(1,1e5,rt[now],rt[to]);
		}
	}
	if (mxv[rt[now]]) ans[now] = col[rt[now]];
}
int main() {
	scanf("%d%d",&n,&m);
	for (int i = 1,u,v;i < n;i++) {
		scanf("%d%d",&u,&v);
		edge[u].push_back(v);
		edge[v].push_back(u);
	}
	init(1,0);
	dfs(1,1);
	for (int u,v,w;m--;) {
		scanf("%d%d%d",&u,&v,&w);
		update(1,1e5,rt[u],w,1);
		update(1,1e5,rt[v],w,1);
		int l = lca(u,v);
		update(1,1e5,rt[l],w,-1);
		update(1,1e5,rt[fa[l]],w,-1);
	}
	solve(1);
	for (int i = 1;i <= n;i++) printf("%d\n",ans[i]);
	return 0;
}
上一篇:洛谷 P3372 线段树1


下一篇:P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并