解题思路:一开始我想用树链剖分,但是感觉最坏的情况也有O(n^2)(如果出题者有意要卡你,也肯定过不了),其实用树上倍增最高复杂度也是O(n^2),如果这棵树是一条链。反正都有被卡的可能性,干脆就打一下树上倍增的模板吧。
#include<cstdio>
#include<string>
#include<vector>
#include<algorithm>
#define N 100009
using namespace std;
vector<int> s[N];
int fa[N][21],h[N],w[N];
void dfs(int u,int p)
{
h[u]=h[p]+1;
fa[u][0]=p;
for(int i=1;i<=20;i++) fa[u][i]=fa[fa[u][i-1]][i-1];
for(int i=0;i<s[u].size();i++)
{
if(s[u][i]==p) continue;
dfs(s[u][i],u);
}
}
int lca(int u,int v)
{
if(h[u]<h[v]) swap(u,v);
int d=h[u]-h[v];
for(int i=0;i<=20;i++)
if((d>>i)&1) u=fa[u][i];
if(u==v) return u;
for(int i=20;i>=0;i--)
if(fa[u][i]!=fa[v][i])
{
u=fa[u][i];v=fa[v][i];
}
return fa[u][0];
}
int main()
{
//freopen("t.txt","r",stdin);
int n,m,a,b,c,d;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i=1;i<=n;i++) s[i].clear();
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
for(int i=0;i<n-1;i++)
{
scanf("%d%d",&a,&b);
s[a].push_back(b);
s[b].push_back(a);
}
dfs(1,0);
while(m--)
{
long long ans=0;
scanf("%d%d%d%d",&a,&b,&c,&d);
int lc=lca(a,b);
for(int i=a;i!=lc;i=fa[i][0]) if(w[i]>=c&&w[i]<=d) ans+=w[i];
for(int i=b;i!=lc;i=fa[i][0]) if(w[i]>=c&&w[i]<=d) ans+=w[i];
if(w[lc]>=c&&w[lc]<=d) ans+=w[lc];
printf("%lld",ans);
if(m) printf(" ");
}
printf("\n");
}
return 0;
}