分析タイトル:
この方法の一つ:
DFSの順で、フェンウィックツリーメンテナンス回ずつ番号が表示され、その子孫より順DFSルートにトラバースする(ルートにトラバースするとき、横断子供たちを参加していない)のため、
uがVのときの統計の祖先の対象、「xはルート、および次のトラバーサルはその子孫が、あるされているノードへのトラバース」を確実にするため、DFS
父親と同じように、再び再帰的思考、計算のリーフノード一端、父親更新した後、彼の父は、更新に貢献します、ビン。
概要:DFSそれを処理するためにおよびサブツリーの根本的な問題
非常に明確なアイデア:主要統計サブツリーを横断する前に、DFS配列上の2つのクエリを作成するには、主要な統計サブツリートラバーサルの寄与は、二つがある引くことサブツリーの寄与
方法2:統計間隔とタイムスタンプのシーケンスとタイムスタンプDFSのツリーの会長、何の問題を考えていません。
ここでのアプローチの方法を置くために、方法2は、コードWAを書いたが、それは確かに交流その日でした!
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
ll a[maxn];
ll sum[maxn],c[maxn];
const int INF = 0x3f3f3f3f;
vector<int> vec;
vector<ll> g[maxn];
int n;
ll k;
//树状数组
int lowbit(int x){
return x & -x;
}
void add(int x, int v){
while (x < maxn){
c[x] += v;
x += lowbit(x);
}
}
int query(int x){
if (x >= maxn)
return 0;
int res = 0;
while (x)
res += c[x], x -= lowbit(x);
return res;
}
int rangeQuery(int l, int r){
return query(r) - query(l - 1);
}
//dfs序上 查询和更新树状数组
void dfs(int x){
int l = lower_bound(vec.begin(),vec.end(),a[x] - k ) - vec.begin(); //找到左边界下标()
int r = lower_bound(vec.begin(),vec.end(),a[x] + k ) - vec.begin(); //找到右边界下标()
if(r >= vec.size() || vec[r] > a[x] + k) --r; //右边界没找到 规定为vec容器的最后一个值
ll cnt1 = rangeQuery(l,r); //先求出 dfs子树前的贡献
add(lower_bound(vec.begin(),vec.end(),a[x]) - vec.begin(),1); //出现次数+1
for(int v : g[x]){
dfs(v);
sum[x] += sum[v]; //加上孩子们的贡献
}
ll cnt2 = rangeQuery(l,r); //再求出 dfs子树后的贡献
sum[x] += cnt2 - cnt1; //两者相减的差 就是子树的贡献了
}
int main(){
scanf("%d %lld",&n,&k);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
vec.push_back(a[i]);
}
//离散化
vec.push_back(-INF);
sort(vec.begin(),vec.end());
vec.erase(unique(vec.begin(),vec.end()),vec.end());
for(int i=1;i<=n-1;i++){
ll fa;
scanf("%lld",&fa);
g[fa].push_back(i+1);
}
dfs(1);
for(int i=1;i<=n;i++) printf("%lld\n",sum[i]);
return 0;
}