题目链接: Jumping Monkey
大致题意
给定一个有 n n n个节点的树, 每个节点有一个权值 w i w_i wi(保证点权两两不同). 节点 a a a可以移动到节点 b b b, 当且仅当 w b w_b wb是 ( a , b ) (a, b) (a,b)最短路径上权值最大的点.
问: 当分别以 k ( k ∈ [ 1 , n ] ) k \ (k \in [1, n]) k (k∈[1,n])为起始点, 最多能到达多少个不同的点.
解题思路
点分治 + BIT
本题解就当存一份代码吧, 隔得太久了, 已经忘了当时比赛的时候是怎么想的了.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;
}