本题思路同第2篇题解,倍增解决,但细节实现可能不同(应该不会有问题吧)。与暴力m遍O(n)树形DP同分……不过是WA不是TLE。
代码如下
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll f[100010][2],a[100010],g[100010][2],h[100010][2][20][2];
int te,fa[100010][20],head[100010],de[100010];
struct edge{
int to,nex;
}e[200010];
void Add(int a,int b){
e[++te].nex=head[a];
e[te].to=b;
head[a]=te;
}
void Dfs1(int x){
for(register int i=0;i<19;i++)fa[x][i+1]=fa[fa[x][i]][i];
for(register int i=head[x];i;i=e[i].nex)
if(e[i].to!=fa[x][0])
fa[e[i].to][0]=x,de[e[i].to]=de[x]+1,Dfs1(e[i].to),f[x][0]+=f[e[i].to][1],f[x][1]+=min(f[e[i].to][0],f[e[i].to][1]);
f[x][1]+=a[x];
}
void Dfs2(int x){
for(register int i=head[x];i;i=e[i].nex)
if(e[i].to!=fa[x][0])
g[e[i].to][0]=f[x][1]+g[x][1]-min(f[e[i].to][0],f[e[i].to][1]),g[e[i].to][1]=min(g[e[i].to][0],g[x][0]+f[x][0]-f[e[i].to][1]),Dfs2(e[i].to);
}
void Cl(int a,int za,int b,int zb){
if(de[a]<de[b])swap(a,b),swap(za,zb);
ll sa[2]={1ll<<62,1ll<<62},sb[2]={1ll<<62,1ll<<62};
sa[za]=f[a][za],sb[zb]=f[b][zb];
// printf("%d %d %lld %lld %lld %lld\n",a,b,sa[0],sa[1],sb[0],sb[1]);
for(register int i=19;i>-1;i--)
if(de[a]-(1<<i)>=de[b]){
ll ta[2]={1ll<<62,1ll<<62};
for(register int k=0;k<2;k++)
for(register int l=0;l<2;l++)
ta[k]=min(ta[k],sa[l]+h[a][l][i][k]);
sa[0]=ta[0],sa[1]=ta[1],a=fa[a][i];
// printf("%d %d %lld %lld %lld %lld\n",a,b,sa[0],sa[1],sb[0],sb[1]);
}
// printf("%d %d\n",a,b);
if(a==b){
printf("%lld\n",sa[zb]+g[b][zb]);
return;
}
for(register int i=19;i>-1;i--)
if(fa[a][i]!=fa[b][i]){
ll ta[2]={1ll<<62,1ll<<62},tb[2]={1ll<<62,1ll<<62};
for(register int k=0;k<2;k++)
for(register int l=0;l<2;l++)
ta[k]=min(ta[k],sa[l]+h[a][l][i][k]),tb[k]=min(tb[k],sb[l]+h[b][l][i][k]);
sa[0]=ta[0],sa[1]=ta[1],sb[0]=tb[0],sb[1]=tb[1],fa[a][i],b=fa[b][i];
}
// printf("%d %d\n",a,b);
printf("%lld\n",min(g[fa[a][0]][0]+f[fa[a][0]][0]-f[a][1]-f[b][1]+sa[1]+sb[1],g[fa[a][0]][1]+f[fa[a][0]][1]-min(f[a][1],f[a][0])-min(f[b][0],f[b][1])+min(sa[0],sa[1])+min(sb[0],sb[1])));
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
char c=getchar();
while(c!='1'&&c!='2'&&c!='3')c=getchar();
for(register int i=1;i<=n;i++)scanf("%d",a+i);
for(register int i=1;i<n;i++){
int a,b;
scanf("%d%d",&a,&b);
Add(a,b);
Add(b,a);
}
Dfs1(1);
Dfs2(1);
for(register int i=1;i<=n;i++){
h[i][0][0][0]=0x3f3f3f3f;
h[i][1][0][0]=f[fa[i][0]][0]-f[i][1];
h[i][1][0][1]=h[i][0][0][1]=f[fa[i][0]][1]-min(f[i][0],f[i][1]);
}
for(register int j=1;j<20;j++)
for(register int i=1;i<=n;i++)
for(register int k=0;k<2;k++)
for(register int l=0;l<2;l++){
h[i][k][j][l]=0x3f3f3f3f;
for(register int o=0;o<2;o++)
h[i][k][j][l]=min(h[i][k][j][l],h[i][k][j-1][o]+h[fa[i][j-1]][o][j-1][l]);
}
while(m--){
int a,b,za,zb;
scanf("%d%d%d%d",&a,&za,&b,&zb);
if(!za&&!zb){
bool bb=0;
for(register int i=head[a];i;i=e[i].nex)
if(e[i].to==b)
bb=1;
if(bb){
puts("-1");
continue;
}
}
Cl(a,za,b,zb);
}
return 0;
}