【BZOJ3307】雨天的尾巴

【题目链接】

【思路要点】

  • 路径\((x,y)\)可以看做路径\((x,root)\)+路径\((y,root)\)-路径\((Lca,root)\)-路径\((father_{Lca},y)\)。
  • 依据这一点进行树上差分和线段树合并即可。
  • 时间复杂度\(O(NLogN)\)(\(N\)、\(M\)同阶)。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int MAXP = 5000005;
const int MAXN = 100005;
const int MAXLOG = 20;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
struct SegmentTree {
	struct Node {
		int lc, rc;
		bool leaf;
		int Max;
	} a[MAXP];
	int n, size;
	void init(int x) {
		n = x;
		size = 0;
	}
	void update(int root) {
		a[root].Max = max(a[a[root].lc].Max, a[a[root].rc].Max);
	}
	void modify(int &root, int l, int r, int val, int d) {
		if (root == 0) root = ++size;
		if (l == r) {
			a[root].leaf = true;
			a[root].Max += d;
			return;
		}
		int mid = (l + r) / 2;
		if (mid >= val) modify(a[root].lc, l, mid, val, d);
		else modify(a[root].rc, mid + 1, r, val, d);
		update(root);
	}
	void modify(int &root, int val, int d) {
		modify(root, 1, n, val, d);
	}
	int merge(int x, int y) {
		if (x == 0 || y == 0) return x + y;
		if (a[x].leaf) {
			a[x].Max += a[y].Max;
			return x;
		}
		a[x].lc = merge(a[x].lc, a[y].lc);
		a[x].rc = merge(a[x].rc, a[y].rc);
		update(x);
		return x;
	}
	int query(int root, int l, int r) {
		if (l == r) return l;
		int mid = (l + r) / 2;
		if (a[a[root].lc].Max >= a[a[root].rc].Max) return query(a[root].lc, l, mid);
		else return query(a[root].rc, mid + 1, r);
	}
	int query(int root) {
		if (a[root].Max == 0) return 0;
		else return query(root, 1, n);
	}
} ST;
vector <int> a[MAXN];
int n, father[MAXN][MAXLOG], depth[MAXN];
int m, x[MAXN], y[MAXN], val[MAXN];
int tot, tmp[MAXN], root[MAXN], ans[MAXN];
void work(int pos, int fa) {
	father[pos][0] = fa;
	depth[pos] = depth[fa] + 1;
	for (int i = 1; i < MAXLOG; i++)
		father[pos][i] = father[father[pos][i - 1]][i - 1];
	for (unsigned i = 0; i < a[pos].size(); i++)
		if (a[pos][i] != fa) work(a[pos][i], pos);
}
int lca(int x, int y) {
	if (depth[x] < depth[y]) swap(x, y);
	for (int i = MAXLOG - 1; i >= 0; i--)
		if (depth[father[x][i]] >= depth[y]) x = father[x][i];
	if (x == y) return x;
	for (int i = MAXLOG - 1; i >= 0; i--)
		if (father[x][i] != father[y][i]) {
			x = father[x][i];
			y = father[y][i];
		}
	return father[x][0];
}
void getans(int pos, int fa) {
	for (unsigned i = 0; i < a[pos].size(); i++)
		if (a[pos][i] != fa) {
			getans(a[pos][i], pos);
			root[pos] = ST.merge(root[pos], root[a[pos][i]]);
		}
	ans[pos] = tmp[ST.query(root[pos])];
}
int main() {
	read(n), read(m);
	for (int i = 1; i <= n - 1; i++) {
		int x, y; read(x), read(y);
		a[x].push_back(y);
		a[y].push_back(x);
	}
	work(1, 0);
	for (int i = 1; i <= m; i++)
		read(x[i]), read(y[i]), read(val[i]), tmp[i] = val[i];
	sort(tmp + 1, tmp + m + 1);
	tot = unique(tmp + 1, tmp + m + 1) - tmp - 1;
	ST.init(tot);
	for (int i = 1; i <= m; i++) {
		int z = lca(x[i], y[i]);
		int num = lower_bound(tmp + 1, tmp + tot + 1, val[i]) - tmp;
		ST.modify(root[x[i]], num, 1);
		ST.modify(root[y[i]], num, 1);
		ST.modify(root[z], num, -1);
		ST.modify(root[father[z][0]], num, -1);
	}
	getans(1, 0);
	for (int i = 1; i <= n; i++)
		writeln(ans[i]);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值