题意:
给出一棵树 父亲节点的权值>儿子节点
1e5组询问 与x号点相连的点[L,R]范围内的点有多少个
对于每个节点来说他所有的儿子都比自己小
那么只需要看这个子树中的L-R的数量 然后接下来是对于这个节点的父亲来说 他需要找到最后一个小于等于R的父亲节点 那么最终答案就是找到的父亲节点的子树中 L-R权值的数量
找父亲我们可以通过倍增来找
统计子树信息 我的写法是一棵暴力的线段树合并 对于线段树合并来说 他是离线算法 高效统计每棵子树的信息
复杂度分析:最高是一颗完美二叉树 从根节点往下分析
每次合并复杂度
s
z
[
u
]
/
2
∗
(
log
(
n
)
)
sz[u]/2*(\log(n))
sz[u]/2∗(log(n))
接下来复杂度其实就和cdq分治很像了
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef int LL;
const int N = 1e6+10,INF=1e9,M=2e5+10;
struct Edge{
int v,next;
}edge[M<<1];
int head[M],tot;
void add(int u,int v){
edge[++tot]={v,head[u]};
head[u]=tot;
}
int a[M];
int fa[M][22];
int root[M];
struct Node{
int l,r;
int sum;
}tr[N<<2];
#define ls tr[u].l
#define rs tr[u].r
int idx,n;
int A[M],An;
int change(int u,LL l,LL r,LL k,LL val){
if(!u){
u=++idx;
}
if(l==r){
tr[u].sum=tr[u].sum+val;
return u;
}
LL mid=l+r>>1;
if(k<=mid)ls=change(ls,l,mid,k,val);
else rs=change(rs,mid+1,r,k,val);
tr[u].sum=tr[ls].sum+tr[rs].sum;
return u;
}
int merge(int u,int v,LL l,LL r){
if(!u||!v)return u|v;
tr[++idx]=tr[u];
u=idx;
if(l==r){
tr[u].sum+=tr[v].sum;
return u;
}
LL mid=l+r>>1;
ls=merge(ls,tr[v].l,l,mid);
rs=merge(rs,tr[v].r,mid+1,r);
tr[u].sum=tr[ls].sum+tr[rs].sum;
return u;
}
LL query(int u,LL l,LL r,LL a,LL b){
if(!u)return 0;
if(a<=l&&r<=b){
return tr[u].sum;
}
LL mid=l+r>>1;
int res=0;
if(a<=mid)res+= query(ls,l,mid,a,b);
if(b>mid) res+= query(rs,mid+1,r,a,b);
tr[u].sum=tr[ls].sum+tr[rs].sum;
return res;
}
void dfs(int u,int father){
for(int i=head[u];i;i=edge[i].next){
int v=edge[i].v;
if(v==father)continue;
fa[v][0]=u;
for(int j=1;j<=20;j++){
fa[v][j]=fa[fa[v][j-1]][j-1];
}
dfs(v,u);
root[u]=merge(root[u],root[v],1,An);
}
root[u]=change(root[u],1,An,a[u],1);
}
int get(int u,int r){
for(int k=20;k>=0;k--){
if(fa[u][k]&&a[fa[u][k]]<=r&&fa[u][k]){
u=fa[u][k];
}
}
return u;
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
A[++An]=a[i];
}
A[++An]=0;
A[++An]=1e9;
sort(A+1,A+1+An);
An=unique(A+1,A+1+An)-(A+1);
for(int i=1;i<=n;i++){
a[i]=lower_bound(A+1,A+1+An,a[i])-A;
}
dfs(1,1);
int m;
scanf("%d",&m);
for(int i=1;i<=m;i++){
int x,l,r;
scanf("%d%d%d",&x,&l,&r);
l=lower_bound(A+1,A+1+An,l)-A;
r=upper_bound(A+1,A+1+An,r)-A;
r--;
if(a[x]<l||a[x]>r){
puts("0");
continue;
}
int t=get(x,r);
printf("%d\n",query(root[t],1,An,l,r));
}
return 0;
}
/*
5
1 2
2 4
1 3
3 5
9 7 4 5 1
9
5 1 9
*/