HDU7136ジャンピングモンキー(分割統治+ツリー配列)

トピックリンク:ジャンピングモンキー

一般的なアイデア

与えられたnの数n個のノードのツリー。各ノードの重みはwiw_iw私は(ポイントの重みがペアで異なることを保証します)ノードaaaをノードbbに移動できますb 、 wbw_bの場合のみwb(a、b)(a、b)、、_b 最短経路上で最大の重みを

質問:k(k∈[1、n])k \(k \ in [1、n])の場合k k [ 1 n ] が開始点であり、最大でいくつの異なるポイントに到達できます。

問題解決のアイデア

分割統治+BIT

この問題の解決策はコードとして保存する必要があります。長すぎて、game.jpgで考えたことを忘れてしまいました。

ACコード

#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;
}

終わり

おすすめ

転載: blog.csdn.net/weixin_45799835/article/details/121341568