2021 Niuke summer multi school training camp 9 E, Eyjafjalla

E,Eyjafjalla

General idea of the topic

You have one 1 1 1 is root n ( 1 ≤ n ≤ 1 0 5 ) n(1\le n\le 10^5) A rooted tree with n(1 ≤ n ≤ 105) nodes, each point has a temperature t i ( 1 ≤ t i ≤ 1 0 9 ) t_i(1\le t_i\le 10^9) ti (1 ≤ ti ≤ 109), and ensure that the temperature from father to son must decrease.

Now there are Q ( 1 ≤ Q ≤ 1 0 5 ) Q(1\le Q\le10^5) Q(1 ≤ Q ≤ 105) queries, each query at point x x x has a heat resistance of [ l , r ] [l,r] [l,r], ask how many points it can spread to at most, and it can spread along the path to the descendant node or to the parent node, if and only if there is a temperature KAtex parse error: undefined control sequence: \ Mbox at position 11: t_ i<l \ \ \ ̲ m ̲ b ̲ o ̲ x ̲ {or}\ \ t_ i> R, so this t i t_i ti# will not be infected, and the virus will be killed here. Now ask how many nodes can be infected at most.

Solution

Test point: multiplication + dsu + tree array

We know that if it doesn't go up for the given query, the problem will become easier. In this way, I have several queries. Each time I query a node, it is greater than its son l l l how many are there. In fact, this is very easy to achieve. We can use the idea of multiplication O ( log ⁡ n ) O(\log n) O(logn) goes all the way up to find the last one less than or equal to r r r, and then for the simplified query, we have the following methods.

We just need to go up from the leaf node d f s dfs dfs can find the answer by maintaining a tree array, but soon we will find a new problem. We have a tree and assume there is 1 → 2 , 1 → 3 1\to 2,1\to3 1 → 2, 1 → 3, so how do we calculate 3 3 When the subtree of 3 answers 2 2 2 what is the contribution of this subtree? Chairman tree? Of course, this can be done. It is also the answer given by the standard answer. However, I think it is easier to use the previous tree array. Let's mention how to deal with this problem with the chairman tree. We timestamp the interval composed of each node and its subtree, and then it becomes a persistent interval query l l The number of l can be maintained by using the chairman tree.

But what if I don't want to use the chairman tree? Another good way to deal with off-line queries on the tree is tree heuristic merging (dsu), which can O ( n log ⁡ n ) O(n\log n) O(nlogn) time deals with the offline problem on the tree. Its most well-known approach is to solve it Q Q Query point on Q-tree u u How many different colors are there in u and its subtree? Does it correspond to our problem, that is, query u u u and its subtree l l How many are there in l? We can use a tree array after discretization O ( log ⁡ n ) O(\log n) O(logn) solution.

So the total time complexity of this problem is O ( n log ⁡ n log ⁡ n ) O(n\log n\log n) O (nlogn), it seems that this problem can be solved by direct line segment tree violence. The data should be weak.

Put a line segment tree to query the timestamp code.

if (L <= l && r <= R) {
    if (mini[rt] >= v)	return 0;
    if (maxi[rt] < v)	return r - l + 1;
}

The following is the code of heuristic merging. Personally, I think it is a very good topic of heuristic merging, which is very similar to the template. The main idea of the author is to maintain it with the chairman tree.

const int N = 1e5 + 7;
ll n, m;
int p[N];

vector<int> G[N];

int fa[N][21], son[N], sz[N];
int a[N], b[N * 4], tot;

void dfs(int u, int father) {
	sz[u] = 1;
	fa[u][0] = father;
	for (int i = 1; i <= 20; ++i) {
		fa[u][i] = fa[fa[u][i - 1]][i - 1];
	}
	for (auto& v : G[u]) {
		if (v == father)	continue;
		dfs(v, u);
		sz[u] += sz[v];
		if (son[u] == 0 || sz[son[u]] < son[v])
			son[u] = v;
	}
}

int ans[N];
vector<pai> query[N];
bool vis[N];

inline int Id(int x) {
	return lower_bound(b + 1, b + 1 + tot, x) - b;
}

int c[N];
inline int lowbit(int x) { return x & (-x); }
inline void add(int i, int x) {
	for (; i <= tot; i += lowbit(i))
		c[i] += x;
}
inline int get(int i) {
	int res = 0;
	for (; i; i -= lowbit(i))	res += c[i];
	return res;
}

void calc(int u, int father) {
	add(Id(a[u]), 1);
	for (auto& v : G[u]) {
		if (v == father || vis[v])	continue; // Note that each node can only be calculated once. Don't count too many
		calc(v, u);
	}
}

void delte(int u, int father) {
	add(Id(a[u]), -1);
	for (auto& v : G[u]) {
		if (v == father)	continue;
		delte(v, u);
	}
}

void dsu(int u, int father, bool op) {
	for (auto& v : G[u]) {
		if (v != father && v != son[u])
			dsu(v, u, false);
	}
	if (son[u] != 0) {
		dsu(son[u], u, true);
	}
	vis[son[u]] = true;
	calc(u, father);
	for (auto& [id, l] : query[u]) {
		int pos = Id(l);
		ans[id] = sz[u] - get(pos - 1);
	}
	vis[son[u]] = false;
	if (!op)	delte(u, father);
}

int solve() {
	n = read();
	for (int i = 1; i < n; ++i) {
		int u = read(), v = read();
		G[u].push_back(v);
		G[v].push_back(u);
	}
	for (int i = 1; i <= n; ++i)	b[i] = a[i] = read();

	sort(b + 1, b + 1 + n);
	tot = unique(b + 1, b + 1 + n) - (b + 1);

	a[0] = INF64;
	dfs(1, 0);

	m = read();
	for (int i = 1; i <= m; ++i) {
		int x = read(), l = read(), r = read();
		if (a[x] < l || a[x] > r)	ans[i] = 0;
		else {
			for (int k = 20; ~k; --k) {
				if (a[fa[x][k]] <= r)	x = fa[x][k];
			}
			query[x].push_back({ i,l });
		}
	}
	dsu(1, 0, false);

	for (int i = 1; i <= m; ++i)	print(ans[i]);

	return 1;
}

Tags: Algorithm

Posted on Fri, 29 Oct 2021 09:07:20 -0400 by echoninja