题意:给定一棵树,求两个点之间路径上的点权和,点权在一定范围内才有效,否则为0
思路:开始T了一发双向BFS,后来想到有个算法叫LCA,可惜没学过,现场学,还用错一个模板,用的是二分搜索找LCA的模板。我是每次加上新到的点的权(范围内),二分这个,更新的点是跳着走的。应该用一步一步往上走的模板,赛后才想到,为时已晚。
每个点有一个深度,找两个点的LCA时,大家先走到一个深度,再一起向上走,直到相同
#include<bits/stdc++.h>
using namespace std;
const int MAX_V = 2e5+5;
const int MAX_LOG_V = 100;
vector<int> G[MAX_V];
int root;
int parent[MAX_V];
int dep[MAX_V];
long long ans;
long long cc[MAX_V],aa[MAX_V];
void dfs(int v,int p,int d)
{
parent[v]=p;
dep[v]=d;
for(int i=0;i<G[v].size();i++)
{
if(G[v][i]!=p)
dfs(G[v][i],v,d+1);
}
}
void init(int V)
{
dfs(root,-1,0);
}
long long is(int x,int c,int d)
{
if(aa[x] >= c && aa[x] <= d)
return aa[x];
else
return 0;
}
int lca(int u,int v,int c,int d)
{
ans += is(u,c,d);
ans += is(v,c,d);
while(dep[u] > dep[v])
{
u = parent[u];
ans += is(u,c,d);
}
while(dep[v] > dep[u])
{
v = parent[v];
ans += is(v,c,d);
}
while(u != v)
{
u = parent[u];
ans += is(u,c,d);
v = parent[v];
ans += is(v,c,d);
}
ans -= is(v,c,d);
return u;
}
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i = 0; i <= n; i++)
G[i].clear();
root = n / 2;
for(int i = 0; i < n; i++)
scanf("%lld",&aa[i]);
for(int i = 1; i < n; i++)
{
int a,b;
scanf("%d%d",&a,&b);
a--;b--;
G[a].push_back(b);
G[b].push_back(a);
}
init(n);
for(int i = 1; i <= m; i++)
{
int a,b,c,d;
scanf("%d%d%d%d",&a,&b,&c,&d);
a--;b--;
ans = 0;
lca(a,b,c,d);
cc[i] = ans;
}
for(int i = 1; i <= m; i++)
printf("%lld%c",cc[i],i==m?'\n':' ');
}
return 0;
}