考虑在点 x x x处爆发 [ l , r ] [l,r] [l,r]的瘟疫且 x ∈ [ l , r ] x\in[l,r] x∈[l,r]
考虑 x x x往上延伸,节点温度不断上升,所以往上的节点不需要考虑下界 l l l的限制
显然可以倍增到一个深度最浅的节点 v v v满足 t v < = r t_v<=r tv<=r,再往上的节点都不符合要求
又因为 v v v子树内的节点温度都小于 t v t_v tv,显然不需要考虑上界 r r r的限制
问题转化为,求出 v v v的子树内有多少节点的温度大于等于 l l l
这个东西可以线段树合并保存每个节点的子树内温度为下标的权值线段树即可
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
const int N = 1e7+10;
vector<int>vec[maxn];
int n,top,x[maxn],l[maxn],r[maxn],t[maxn],li[N],fa[maxn][22];
int get(int x,int mx)
{
for(int i=20;i>=0;i--)
if( t[ fa[x][i] ]<=mx ) x = fa[x][i];
return x;
}
int sum[N],ls[N],rs[N],root[maxn],id;
int merge(int x,int y,int l,int r)
{
if( !x || !y ) return x|y;
int p = ++id,mid = l+r>>1;
if( l==r )
{
sum[p] = sum[x]+sum[y];
return p;
}
ls[p] = merge( ls[x],ls[y],l,mid );
rs[p] = merge( rs[x],rs[y],mid+1,r );
sum[p] = sum[ls[p]]+sum[rs[p]];
return p;
}
int ask(int rt,int l,int r,int L,int R)
{
if( !rt || l>R || r<L ) return 0;
if( l>=L && r<=R ) return sum[rt];
int mid = l+r>>1;
return ask( ls[rt],l,mid,L,R )+ask( rs[rt],mid+1,r,L,R );
}
void update(int &rt,int l,int r,int val)
{
if( !rt ) rt = ++id;
if( l==r && l==val ) { sum[rt]++; return; }
int mid = l+r>>1;
if( val<=mid ) update( ls[rt],l,mid,val );
else update( rs[rt],mid+1,r,val );
sum[rt] = sum[ls[rt]]+sum[rs[rt]];
}
void dfs(int u,int father)
{
update( root[u],1,top,t[u] );
fa[u][0] = father;
for(int i=1;i<=20;i++) fa[u][i] = fa[fa[u][i-1]][i-1];
for(auto v:vec[u] )
{
if( v==father ) continue;
dfs( v,u );
root[u] = merge( root[u],root[v],1,top );
}
}
int main()
{
ios::sync_with_stdio( false );
cin >> n;
for(int i=1;i<n;i++)
{
int l,r; cin >> l >> r;
vec[l].push_back( r ); vec[r].push_back( l );
}
for(int i=1;i<=n;i++) cin >> t[i], li[++top] = t[i];
int q; cin >> q;
for(int i=1;i<=q;i++) cin >> x[i] >> l[i] >> r[i];
for(int i=1;i<=q;i++) li[++top] = l[i], li[++top] = r[i];
sort( li+1,li+1+top );
top = unique( li+1,li+1+top )-li-1;
for(int i=1;i<=n;i++)
t[i] = lower_bound( li+1,li+1+top,t[i] )-li;
for(int i=1;i<=q;i++)
{
l[i] = lower_bound( li+1,li+1+top,l[i] )-li;
r[i] = lower_bound( li+1,li+1+top,r[i] )-li;
}
dfs( 1,1 );
for(int i=1;i<=q;i++)
{
int u = get( x[i],r[i] );//刚好小于等于r的那个节点
if( t[ x[i] ]>r[i] || t[ x[i] ]<l[i] ) cout << 0 << endl;
else cout << ask( root[u],1,top,l[i],r[i] ) << endl;
}
}