题意: 题目给了一个
n
个点的完全二叉树,每个节点都有他的价值
定义这棵树的价值为:每一个深度的价值为这个深度所有节点的价值总和,树的价值为 所有深度中价值最大的。
然后有
m
个询问,每个询问是一个节点
数据范围:
1≤n≤1e5,1≤m≤1e5,1≤w≤1e4
分析:因为给定的树是完全二叉树,所以对于某一层的和,可以采用区间求和的方式获得。
这样,对于每个询问,我们从根节点开始往下,第
i
层点的范围为
如果包含被查询的子树,就将其减去。知道这些,剩下的就是如何建出这颗完全二叉树了。
我采用的方法是,先一个
dfs
处理出每个节点的子树大小。再一个
dfs
标号,
如果
siza≥sizb
那么
a
当左子树,反之
一颗
n
个节点的完全二叉树深度最多
以下是代码:
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 100005;
int id[MAXN], tot = 0;
int val[MAXN];
int n, m, w, a, b, c, q;
int st[MAXN][20];
int siz[MAXN];
bool vis[MAXN];
vector<int>vec[MAXN];
void pre(int cur,int now) {
siz[now] = 1;
for (int i = 0; i < vec[now].size(); ++i) {
int v = vec[now][i];
pre(cur + 1, v);
siz[now] += siz[v];
}
}
void dfs(int now) {
if (vec[now].size() == 2) {
int a = vec[now][0], b = vec[now][1];
if (siz[a] >= siz[b])id[a] = id[now] * 2, id[b] = id[now] * 2 + 1;
else id[a] = id[now] * 2 + 1, id[b] = id[now] * 2;
dfs(a); dfs(b);
}
else if (vec[now].size() == 1)id[vec[now][0]] = id[now] * 2, dfs(vec[now][0]);
else
{
return;
}
}
void RMQ() {
for (int i = 1; i < 20; ++i) {
if ((1 << i) > n)break;
for (int j = 1; j <= n; ++j) {
if (j + (1 << (i - 1)) > n)break;
st[j][i] = st[j][i - 1] + st[j + (1 << (i - 1))][i - 1];
}
}
}
int query(int l, int r) {
int res = 0;
for (int i = 20; i >= 0; --i) {
if (l + (1 << i) > r)continue;
else
{
res += st[l][i];
l += (1 << i);
}
}
return res + st[r][0];
}
int main()
{
scanf("%d%d%d", &n, &m, &w); val[1] = w;
for (int i = 0; i < n - 1; ++i) {
scanf("%d%d%d", &a, &b, &c);
vec[b].push_back(a);
val[a] = c;
}
pre(1, 1); id[1] = 1;
dfs(1);
for (int i = 1; i <= n; ++i) {
st[id[i]][0] = val[i];
}
RMQ();
while (m--) {
scanf("%d", &q);
int now = 1, siz = 1;
int qnow = id[q], qsiz = 1;
int ans = 0;
while (now <= n) {
if (qnow >= now && qnow <= min(n, now + siz - 1)) {
ans = max(ans, query(now, min(n, now + siz - 1)) - query(qnow, min(n, qnow + qsiz - 1)));
qnow *= 2; qsiz *= 2;
}
else
{
ans = max(ans, query(now, min(n, now + siz - 1)));
}
now *= 2, siz *= 2;
}
printf("%d\n", ans);
}
}