题目链接:
题意:
n个城市呈一个树形结构,1号城市是树根,越接近1号城市温度越高,从树根往下,温度满足递减的关系,现有一种生存温度在[L,R]区间病毒在X号城市出现,如果相邻城市的温度在[L,R]区间,则这个城市也会感染病毒。
题目首先给出城市个数n,之后的n-1行是树的边,再之后的一行是n个整数,代表n个城市的温度。
接下来给出m次询问,询问之间是相互独立的,每次询问有三个整数x,l,r,表示在x点爆发一种生存温度在[l,r]的病毒,输出最终感染的城市个数。
思路:
我们知道病毒是沿着树链传播的,沿树链向上,温度递增,沿树链向下,温度递减。也就是说我向上传播传到某个点z时达到最大的t<=R,在往上传播时城市的温度t已经大于R了,这时上面的城市肯定感染不上病毒了,所以在以z为根节点的子树中所有满足温度大于等于L的城市就是最终感染的城市。
如何查找沿树链往上走,最大满足t<=R的城市z呢,我们可以通过倍增法()向上爬去查找。
找到z后如何查找以z为根节点的子树中所有满足温度大于等于L的城市个数呢,我们可以通过线段树(或者主席树)查询一段区间内大于某个值的点的个数,所以我们要让z为根节点的子树对应的区间是连续的,通过结点的dfs序建立线段树就可以做到。
样例:
输入
4
1 2
1 3
2 4
10 8 7 6
3
1 10 10
2 6 7
3 7 10
输出
1
0
3
代码:
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
const int M=2*N;
const int inf=1e9+10;
int n,q;
typedef struct Node{
int l,r,mi,ma;
}Node;
Node tr[N*4];
int w[N],t[N];
int h[N],to[M],ne[M],cnt;
int id[N],R[N],idx[N],dfn,fa[N][21];
void init(){
memset(h,-1,sizeof(h));
cnt=0;
t[0]=inf;
}
void add_edge(int u,int v){
to[cnt]=v;
ne[cnt]=h[u];
h[u]=cnt++;
}
void dfs(int u,int fat){
id[u]=++dfn;
idx[dfn]=u;
w[dfn]=t[u];
fa[u][0]=fat;
for(int i=1;i<=20;i++){
fa[u][i]=fa[fa[u][i-1]][i-1];
}
for(int i=h[u];i!=-1;i=ne[i]){
int v=to[i];
if(v!=fat){
dfs(v,u);
}
}
R[u]=dfn;
}
int query_up(int u,int mat){
for(int i=20;i>=0;i--){
if(t[fa[u][i]]<=mat)
u=fa[u][i];
}
return u;
}
void pushup(int u){
tr[u].ma=max(tr[u<<1].ma,tr[u<<1|1].ma);
tr[u].mi=min(tr[u<<1].mi,tr[u<<1|1].mi);
}
void build(int u,int l,int r){
tr[u].l=l,tr[u].r=r;
if(l==r){
tr[u].ma=tr[u].mi=w[l];
return ;
}
int mid=(l+r)>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
pushup(u);
}
int query(int u,int l,int r,int mit){
// cout<<"lr:"<<tr[u].l<<" "<<tr[u].r<<" "<<tr[u].mi<<endl;
if(tr[u].l>=l&&tr[u].r<=r&&tr[u].mi>=mit){
return tr[u].r-tr[u].l+1;
}
if(tr[u].l==tr[u].r)
return 0;
int mid=(tr[u].l+tr[u].r)>>1;
int res=0;
if(l<=mid&&tr[u<<1].ma>=mit)
res+=query(u<<1,l,r,mit);
if(r>mid&&tr[u<<1|1].ma>=mit)
res+=query(u<<1|1,l,r,mit);
return res;
}
int main(){
init();
scanf("%d",&n);
int u,v;
for(int i=1;i<n;i++){
scanf("%d%d",&u,&v);
add_edge(u,v);
add_edge(v,u);
}
for(int i=1;i<=n;i++){
scanf("%d",&t[i]);
}
dfs(1,0);
build(1,1,n);
scanf("%d",&q);
int x,l,r,z,ans;
while(q--){
scanf("%d%d%d",&x,&l,&r);
if(t[x]>r||t[x]<l){
printf("0\n");
continue;
}
z=query_up(x,r);
ans=query(1,id[z],R[z],l);
printf("%d\n",ans);
}
}