HDU7136 Jumping Monkey (Divide and Conquer + Tree Array)

Topic link: Jumping Monkey

general idea

Given a number of nA tree of n nodes, each node has a weightwi w_iwi(Guaranteed that the point weights are different in pairs). Node aaa can be moved to nodebbb , if and only ifwb w_bwbis ( a , b ) (a, b)(a,b ) The point with the largestweight on the shortest path.

Question: When k ( k ∈ [ 1 , n ] ) k \ (k \in [1, n])k(k [1,n ] ) is the starting point, and how many different points can be reached at most.

Problem solving ideas

Divide and conquer + BIT

The solution to this problem should be saved as a code. It has been too long, and I have forgotten what I thought during the game.jpg

AC code

#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
typedef long long ll;
const int N = 1E5 + 10;
int n;
vector<int> edge[N];
bool vis[N];
int w[N], res[N];

vector<int> num;
int find(int x) {
    
     return lower_bound(num.begin(), num.end(), x) - num.begin(); }


int t[N];
int lowbit(int x) {
    
     return x & -x; }
void add(int x, int c) {
    
    
	for (int i = x; i <= n; i += lowbit(i)) t[i] += c;
}
int ask(int x) {
    
    
	int res = 0;
	for (int i = x; i; i -= lowbit(i)) res += t[i];
	return res;
}
int ask(int l, int r) {
    
     return ask(r) - ask(l - 1); }


int get_size(int x, int fa) {
    
    
	if (vis[x]) return 0;
	int res = 1;
	for (auto& to : edge[x]) {
    
    
		if (to == fa) continue;
		res += get_size(to, x);
	}
	return res;
}
int get_wc(int x, int fa, int all, int& wc) {
    
    
	if (vis[x]) return 0;

	int sum = 1, fmax = 0;
	for (auto& to : edge[x]) {
    
    
		if (to == fa) continue;
		int temp = get_wc(to, x, all, wc);
		sum += temp;
		fmax = max(fmax, temp);
	}
	fmax = max(fmax, all - sum);
	if (fmax <= all / 2) wc = x;
	return sum;
}


vector<int> vson[N];
void get_val_big(int x, int fa, int mval, vector<int>& v) {
    
    
	if (vis[x]) return;
	if (w[x] > mval) v.push_back(w[x]), mval = w[x];

	for (auto& to : edge[x]) {
    
    
		if (to == fa) continue;
		get_val_big(to, x, mval, v);
	}
}
void get_val_small(int x, int fa, int mval) {
    
    
	if (vis[x] or w[x] > mval) return;
	res[x]++;

	for (auto& to : edge[x]) {
    
    
		if (to == fa) continue;
		get_val_small(to, x, mval);
	}
}

void calc(int x, int fa, int mval) {
    
    
	if (vis[x]) return;
	mval = max(mval, w[x]);

	if (mval + 1 <= n) res[x] += ask(mval + 1, n);

	for (auto& to : edge[x]) {
    
    
		if (to == fa) continue;
		calc(to, x, mval);
	}
}
void fact(int x) {
    
    
	if (vis[x]) return;

	get_wc(x, -1, get_size(x, -1), x);
	vis[x] = 1;

	for (auto& to : edge[x]) {
    
    
		vson[to].clear();
		get_val_big(to, x, w[x], vson[to]);
		res[x] += vson[to].size();

		for (auto& op : vson[to]) add(op, 1);
	}

	for (auto& to : edge[x]) get_val_small(to, x, w[x]);

	for (auto& to : edge[x]) {
    
    
		for (auto& op : vson[to]) add(op, -1);

		calc(to, x, w[x]);

		for (auto& op : vson[to]) add(op, 1);
	}

	for (auto& to : edge[x]) {
    
    
		for (auto& op : vson[to]) add(op, -1);
	}

	for (auto& to : edge[x]) fact(to);
}
int main()
{
    
    
	int T; cin >> T;
	while (T--) {
    
    
		scanf("%d", &n);

		rep(i, n) edge[i].clear(), vis[i] = 0, res[i] = 1;

		rep(i, n - 1) {
    
    
			int a, b; scanf("%d %d", &a, &b);
			edge[a].push_back(b);
			edge[b].push_back(a);
		}

		num.clear(); num.push_back(-0x3f3f3f3f);
		rep(i, n) scanf("%d", &w[i]), num.push_back(w[i]);
		sort(num.begin(), num.end());

		rep(i, n) w[i] = find(w[i]);

		fact(1);

		rep(i, n) printf("%d\n", res[i]);
	}

	return 0;
}

END

Guess you like

Origin blog.csdn.net/weixin_45799835/article/details/121341568