题目链接
题目大意
火山国家有
n
n
n 个城市,编号为
1
1
1 到
n
n
n ,城市
1
1
1 是首都,有一座大火山。城市
i
i
i 的温度是
t
i
t_i
ti 。
n
n
n 个城市用
n
−
1
n-1
n−1 条无向边相连,第
i
i
i 条边连接城市
u
i
u_i
ui 和
v
i
v_i
vi 。如果
u
i
u_i
ui 比
v
i
v_i
vi更接近首都,则
t
u
i
>
t
v
i
t_{u_i}>t_{v_i}
tui>tvi。首都的温度是最高的。
如果在城市
x
x
x爆发生存温度为
[
l
,
r
]
[l,r]
[l,r] 的病毒,求会感染多少城市。
若一个城市的温度位于
[
l
,
r
]
[l,r]
[l,r]之内,且它与另一个受感染的城市相连,则它也会被感染。
题解
由题目可得,整个国家是一个有
n
−
1
n-1
n−1条边的树。
且深度越小的节点温度越大,反之则更小。
我们用DFS序来储存这一棵树,则可以以较小的复杂度查找向上或向下的节点。
如果在城市
x
x
x 爆发病毒,那么会影响到它附近节点 废话 ,它有两种可能,一种是向上查找,一种是向下查找。
由于向上查找的可能遇到其他能向下找的点,所以我们优先向上查找,我们用倍增查询能符合温度条件的深度最小的节点,然后通过线段树查找符合节点。
由于查询过大,我们将它离线,用前缀和将它保存下来,因为节点可能为
1
0
9
10^9
109 ,所以我们通过离散化记录。
参考代码
#include<bits/stdc++.h>
#define pb push_back
#define ll long long
#define FOR(i,n,m) for(int i=n;i<=m;i++)
using namespace std;
const int N=1e5+5;
void read(int &x)
{
int ret=0;
char c=getchar();
while(!isdigit(c))
c=getchar();
while(isdigit(c))
ret=ret*10+c-'0',c=getchar();
x=ret;
}
struct p{
int l,r,sum;
}segtree[N*3<<2];
struct up{
int id,num;
};
int dfn[N],edn[N],node[N],f[N][30],t[N],ans[N],b[N];
int cnt,n,m,q;
map<int,int>mp;
set<int> s;
vector<int> v[N];
vector<up> l[N],r[N];
void pushup(int x)
{
segtree[x].sum=segtree[x<<1].sum+segtree[x<<1|1].sum;
}
void build(int x,int l,int r)
{
segtree[x].l=l;
segtree[x].r=r;
segtree[x].sum=0;
if(l==r)
return;
int mid=l+r>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
}
int query(int x,int l,int r)
{
if(segtree[x].l==l && segtree[x].r==r)
return segtree[x].sum;
int mid=segtree[x].l+segtree[x].r>>1;
if(r<=mid)
return query(x<<1,l,r);
if(l>mid)
return query(x<<1|1,l,r);
return query(x<<1,l,mid)+query(x<<1|1,mid+1,r);
}
void update(int x,int q)
{
if(segtree[x].l==q && segtree[x].r==q)
{
segtree[x].sum++;
return;
}
int mid=segtree[x].l+segtree[x].r>>1;
if(q<=mid)
update(x<<1,q);
else
update(x<<1|1,q);
pushup(x);
}
void dfs(int x,int fa) //DFS序
{
dfn[x]=++cnt;
node[cnt]=x;
f[x][0]=fa;
FOR(i,1,20)
f[x][i]=f[f[x][i-1]][i-1];
FOR(i,0,v[x].size()-1)
{
if(v[x][i]==fa)
continue;
dfs(v[x][i],x);
}
edn[x]=cnt;
}
int main()
{
read(n);
FOR(i,1,n-1)
{
int x,y;
read(x);
read(y);
v[x].pb(y);
v[y].pb(x);
}
FOR(i,1,n)
{
read(t[i]);
s.insert(t[i]);
}
dfs(1,0);
read(m);
FOR(i,1,m)
{
int x,xl,xr;
read(x);
read(xl);
read(xr);
s.insert(xl);
if(t[x]<xl || t[x]>xr)
continue;
for(int j=20;j>=0;j--)
if(t[f[x][j]]<=xr && f[x][j]) //求符合条件里面深度最小的
x=f[x][j];
l[dfn[x]-1].push_back(up{i,xl}); //前缀
r[edn[x]].push_back(up{i,xl});
}
int t1=1;
set<int>::iterator it;
for(it=s.begin();it!=s.end();it++) //离散化
mp[*it]=t1++;
q=s.size();
build(1,1,q);
FOR(i,1,n) //计算
{
update(1,mp[t[node[i]]]);
if(l[i].size())
FOR(j,0,l[i].size()-1)
ans[l[i][j].id]=query(1,mp[l[i][j].num],q);
if(r[i].size())
FOR(j,0,r[i].size()-1)
ans[r[i][j].id]=query(1,mp[r[i][j].num],q)-ans[r[i][j].id];
}
FOR(i,1,m)
printf("%d\n",ans[i]);
return 0;
}