HDU 5029 Relief grain

题意:

一棵树  m次染色  每次染色一条路径  颜色不会覆盖会积累  问每个点覆盖次数最多的颜色是什么

思路:

树上路径操作不是树链剖分就是LCT  对于每次染色  相当于让那种颜色的权值+1

一般的熟练剖分都是将树剖成线段然后放在线段树上  这题只是剖成线段  然后对于路径的染色  就变成了对多个线段的染色

由于剖分已经使树变成了线性的结构  因此我们可以利用“头加尾减”的方式维护  即  如果染色[u,v]那么u处++然后v+1处--

由于本题有多种颜色  为了快速解决区间更新和求最大值问题我们需要使用线段树  即维护权值线段树  然后从头到尾扫一遍即可

代码:

#pragma comment(linker,"/STACk:10240000,10240000")
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<cassert>
#include<vector>
#include<set>
#include<map>
#include<queue>
using namespace std;
typedef long long LL;
#define N 100010
#define L(x) (x<<1)
#define R(x) ((x<<1)|1)
#define MI(x,y) ((x+y)>>1)

int n, m, tot, idx;
int head[N], pre[N], size[N], dep[N], hson[N], top[N], tid[N], ftid[N], ans[N];
struct Edge {
	int u, v, next;
} ed[N * 2];
struct Add {
	int c, v, next;
} ad[N * 40];
struct Tree {
	int l, r, v;
} d[N * 4];

void addedge(int u, int v) {
	ed[tot].u = u;
	ed[tot].v = v;
	ed[tot].next = head[u];
	head[u] = tot++;
}

void add(int u, int c, int v) {
	ad[tot].c = c;
	ad[tot].v = v;
	ad[tot].next = head[u];
	head[u] = tot++;
}

void dfs1(int u, int fa) {
	pre[u] = fa;
	size[u] = 1;
	dep[u] = dep[fa] + 1;
	hson[u] = 0;
	for (int i = head[u]; ~i; i = ed[i].next) {
		int v = ed[i].v;
		if (v != fa) {
			dfs1(v, u);
			if (size[v] > size[hson[u]])
				hson[u] = v;
			size[u] += size[v];
		}
	}
}

void dfs2(int u, int tp) {
	tid[u] = idx;
	ftid[idx] = u;
	idx++;
	top[u] = tp;
	if (hson[u])
		dfs2(hson[u], tp);
	for (int i = head[u]; ~i; i = ed[i].next) {
		int v = ed[i].v;
		if (v != pre[u] && v != hson[u])
			dfs2(v, v);
	}
}

void Update(int u, int v, int c) {
	int fu = top[u], fv = top[v];
	while (fu != fv) {
		if (dep[fu] >= dep[fv]) {
			add(tid[fu], c, 1);
			add(tid[u] + 1, c, -1);
			u = pre[fu];
			fu = top[u];
		} else {
			add(tid[fv], c, 1);
			add(tid[v] + 1, c, -1);
			v = pre[fv];
			fv = top[v];
		}
	}
	if (dep[u] > dep[v])
		swap(u, v);
	add(tid[u], c, 1);
	add(tid[v] + 1, c, -1);
}

void build(int l, int r, int i) {
	d[i].l = l;
	d[i].r = r;
	d[i].v = 0;
	if (l == r)
		return;
	int mid = MI(l,r);
	build(l, mid, L(i));
	build(mid + 1, r, R(i));
}

void up(int i) {
	d[i].v = max(d[L(i)].v, d[R(i)].v);
}

void update(int p, int i, int v) {
	if (d[i].l == d[i].r) {
		d[i].v += v;
		return;
	}
	int mid = MI(d[i].l,d[i].r);
	if (p <= mid)
		update(p, L(i), v);
	else
		update(p, R(i), v);
	up(i);
}

int query(int i) {
	if (d[i].l == d[i].r)
		return d[i].l;
	if (d[i].v == d[L(i)].v)
		return query(L(i));
	else
		return query(R(i));
}

int main() {
	int i, u, v, c;
	while (~scanf("%d%d", &n, &m)) {
		if (!n && !m)
			break;
		tot = 0;
		memset(head, -1, sizeof(head));
		for (i = 1; i < n; i++) {
			scanf("%d%d", &u, &v);
			addedge(u, v);
			addedge(v, u);
		}
		dfs1(1, 0);
		idx = 1;
		dfs2(1, 1);
		tot = 0;
		memset(head, -1, sizeof(head));
		for (i = 1; i <= m; i++) {
			scanf("%d%d%d", &u, &v, &c);
			Update(u, v, c);
		}
		build(0, 100001, 1);
		for (u = 1; u <= n; u++) {
			for (i = head[u]; ~i; i = ad[i].next)
				update(ad[i].c, 1, ad[i].v);
			ans[ftid[u]] = query(1);
		}
		for (i = 1; i <= n; i++) {
			printf("%d\n", ans[i]);
			assert(ans[i] >= 0 && ans[i] <= 100000);
		}
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值