【JZOJ3397】【GDOI2014模拟】雨天的尾巴

题目大意

给你一棵(n)个点的树,有(m)个操作,每次操作将(x)(y)的路径上的每个点都放入一个颜色为(z)的球。你需要求出最后每个点里个数最多的球是哪种颜色的。

分析

通过树链剖分把树上路径转化为若干区间,把树上问题转化为区间问题,然后结合差分思想,在左端点加上(+z)标记,在右端点(+1)的位置加上(-z)标记,我们从左往右做,用线段树维护当前出现次数最多的颜色,时间复杂度(O(nlog^2n))。最好将颜色离散化,这样线段树就不必动态开点了。

Code

#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define lson rt << 1
#define rson rt << 1 | 1
using namespace std;

const int N = 100007;

int n, m, len, x[N], y[N], z[N], arr[N], ans[N];
int tot, cnt, st[N], to[N << 1], nx[N << 1], son[N], top[N], dfn[N], fa[N], size[N], ord[N], dep[N];
void add(int u, int v) { to[++tot] = v, nx[tot] = st[u], st[u] = tot; }
vector<int> lis[N];

void dfs(int u)
{
	size[u] = 1;
	for (int i = st[u]; i; i = nx[i])
		if (to[i] != fa[u])
		{
			dep[to[i]] = dep[u] + 1, fa[to[i]] = u, dfs(to[i]), size[u] += size[to[i]];
			if (size[to[i]] > size[son[u]]) son[u] = to[i];
		}
}
void dfs2(int u, int tp)
{
	dfn[u] = ++cnt, ord[cnt] = u, top[u] = tp;
	if (son[u]) dfs2(son[u], tp);
	for (int i = st[u]; i; i = nx[i]) if (to[i] != fa[u] && to[i] != son[u]) dfs2(to[i], to[i]);
}
struct note { int id, cnt; } tr[N * 4];
note max(note a, note b)
{
	if (a.cnt == b.cnt) return a.id < b.id ? a : b;
	return a.cnt > b.cnt ? a : b;
}
void build(int rt, int l, int r)
{
	if (l == r) { tr[rt] = (note){l, 0}; return; }
	int mid = l + r >> 1;
	build(lson, l, mid), build(rson, mid + 1, r);
}
void ins(int rt, int l, int r, int po, int v)
{
	if (l == r) { tr[rt].cnt += v; return; }
	int mid = l + r >> 1;
	if (po <= mid) ins(lson, l, mid, po, v);
	else ins(rson, mid + 1, r, po, v);
	tr[rt] = max(tr[lson], tr[rson]);
}

int main()
{
	scanf("%d%d", &n, &m);
	for (int i = 1, u, v; i < n; i++) scanf("%d%d", &u, &v), add(u, v), add(v, u);
	dep[1] = 1, dfs(1), dfs2(1, 1);
	for (int i = 1; i <= m; i++) scanf("%d%d%d", &x[i], &y[i], &z[i]), arr[++len] = z[i];
	sort(arr + 1, arr + len + 1);
	len = unique(arr + 1, arr + len + 1) - arr - 1;
	for (int i = 1, u, v, w; i <= m; i++)
	{
		u = x[i], v = y[i], w = lower_bound(arr + 1, arr + len + 1, z[i]) - arr;
		while (top[u] != top[v])
		{
			if (dep[top[u]] < dep[top[v]]) swap(u, v);
			lis[dfn[top[u]]].push_back(w), lis[dfn[u] + 1].push_back(-w);
			u = fa[top[u]];
		}
		if (dep[u] < dep[v]) swap(u, v);
		lis[dfn[v]].push_back(w), lis[dfn[u] + 1].push_back(-w);
	}
	build(1, 1, len);
	for (int i = 1; i <= n; i++)
	{
		int sz = lis[i].size();
		for (int j = 0, k; j < sz; j++)
		{
			k = lis[i][j];
			if (k > 0) ins(1, 1, len, k, 1);
			else ins(1, 1, len, -k, -1);
		}
		ans[ord[i]] = arr[tr[1].cnt ? tr[1].id : 0];
	}
	for (int i = 1; i <= n; i++) printf("%d
", ans[i]);
	return 0;
}
原文地址:https://www.cnblogs.com/zjlcnblogs/p/11178605.html