题意:
给你一棵树,每个节点有一个价值,要执行m次询问,每次询问输入四个数,s,t,a,b,求解s到t的最短路,并把路径上节点的价值在[a,b]之间的价值求和输出。
思路:
对每组询问,求LCA(开始询问前先以1为根节点dfs一遍,确定每个节点的高度,开始每组询问时,根据高度差迭代求lca,详情看代码),并在求解过程判断价值符不符合要求。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+7;
ll ans[maxn],arr[maxn];
int height[maxn],fa[maxn];
vector<int> e[maxn];
int n,m;
void dfs(int u,int f,int h)
{
height[u] = h;
fa[u] = f;
int len = e[u].size();
for(int i = 0;i<len;i++)
{
int v= e[u][i];
if(v!=f)
{
dfs(v,u,h+1);
}
}
}
ll solve(int s,int t,int a,int b)
{
ll res = 0;
if(t==1)
{
while(s!=0)
{
if(arr[s]>=a&&arr[s]<=b)
res+=arr[s];
s = fa[s];
}
return res;
}
if(s==1)
{
while(t!=0)
{
if(arr[t]>=a&&arr[t]<=b)
res+=arr[t];
t = fa[t];
}
return res;
}
while(1)
{
if(height[t]==height[s])
{
if(t==s)
{
if(arr[s]>=a&&arr[s]<=b)
res+=arr[s];
return res;
}
else
{
if(arr[s]>=a&&arr[s]<=b)
res+=arr[s];
s = fa[s];
}
}
else if(height[s]>height[t])
{
if(arr[s]>=a&&arr[s]<=b)
res+=arr[s];
s = fa[s];
}
else
{
if(arr[t]>=a&&arr[t]<=b)
res+=arr[t];
t = fa[t];
}
}
return res;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
for(int i = 1;i<=n;i++)
e[i].clear();
for(int i = 1;i<=n;i++)
scanf("%lld",arr+i);
for(int i = 0;i<n-1;i++)
{
int u,v;
scanf("%d%d",&u,&v);
e[u].push_back(v);
e[v].push_back(u);
}
dfs(1,0,1);
for(int i = 0;i<m;i++)
{
int s,t,a,b;
scanf("%d%d%d%d",&s,&t,&a,&b);
ans[i] = solve(s,t,a,b);
}
for(int i= 0;i<m;i++)
{
if(i!=m-1)
printf("%lld ",ans[i]);
else
printf("%lld\n",ans[i]);
}
}
return 0;
}