考虑一次询问,显然 DP,设 \(f_{u,0/1}\) 表示走路/坐船到 \(u\) 点的最小花费即可。
多次询问,考虑维护矩阵,扩展矩阵快速幂,倍增处理询问。比如对于一条顺流的边 \(i\),可以构造矩阵:
\[\begin{bmatrix}
a_i&L+a_i-z_i\\
a_i&a_i-z_i
\end{bmatrix}
\]
对每个点 \(u\) 维护 \(up_{u,i}\) 和 \(dw_{u,i}\) 表示从 \(u\) 向上走到 \(2^i\) 级祖先的矩阵和从 \(2^i\) 级祖先向下走到 \(u\) 的矩阵。时间复杂度 \(O((N+T)\log N)\)。
#include<bits/stdc++.h>
#define ll long long
#define il inlineusing namespace std;
namespace asbt{
namespace cplx{bool begin;}
const int maxn=2e5+5;
const ll inf=0x3f3f3f3f3f3f3f3f;
int n,m,q,enm,hd[maxn];
int anc[maxn][22],dep[maxn];
struct edge{int v,nxt;ll w,d;bool typ;
}e[maxn<<1];
il void addedge(int u,int v,ll w,ll d,bool typ){e[++enm]=(edge){v,hd[u],w,d,typ};hd[u]=enm;
}
struct juz{ll mat[2][2];juz(){mat[0][0]=mat[0][1]=mat[1][0]=mat[1][1]=0;}il ll*operator[](int x){return mat[x];}il juz operator*(juz x)const{juz res;res[0][0]=res[0][1]=res[1][0]=res[1][1]=inf;for(int i=0;i<=1;i++){for(int j=0;j<=1;j++){for(int k=0;k<=1;k++){res[i][j]=min(res[i][j],mat[i][k]+x[k][j]);}}}return res;}
}up[maxn][22],dw[maxn][22];
il void dfs(int u,int fa){anc[u][0]=fa,dep[u]=dep[fa]+1;for(int i=1;i<=20;i++){anc[u][i]=anc[anc[u][i-1]][i-1];up[u][i]=up[u][i-1]*up[anc[u][i-1]][i-1];dw[u][i]=dw[anc[u][i-1]][i-1]*dw[u][i-1];}for(int i=hd[u],v,w,d,typ;i;i=e[i].nxt){v=e[i].v,w=e[i].w,d=e[i].d,typ=e[i].typ;if(v==fa){continue;}up[v][0][0][0]=up[v][0][1][0]=w;dw[v][0][0][0]=dw[v][0][1][0]=w;if(typ){up[v][0][0][1]=m+w+d;up[v][0][1][1]=w+d;dw[v][0][0][1]=m+w-d;dw[v][0][1][1]=w-d;}else{up[v][0][0][1]=m+w-d;up[v][0][1][1]=w-d;dw[v][0][0][1]=m+w+d;dw[v][0][1][1]=w+d;}dfs(v,u);}
}
namespace cplx{bool end;il double usdmem(){return (&begin-&end)/1048576.0;}
}
int main(){ios::sync_with_stdio(0),cin.tie(0);cin>>n>>m>>q;for(int i=1,u,v,w,d,typ;i<n;i++){cin>>u>>v>>w>>d>>typ;addedge(u,v,w,d,typ);addedge(v,u,w,d,typ^1);}dfs(1,0);
// for(int i=1;i<=n;i++){
// for(int j=0;j<=1;j++){
// cout<<up[i][j][0][0]<<" "<<up[i][j][0][1]<<" ";
// }
// puts("");
// for(int j=0;j<=1;j++){
// cout<<up[i][j][1][0]<<" "<<up[i][j][1][1]<<" ";
// }
// puts("");
// }
// for(int i=1;i<=n;i++){
// for(int j=0;j<=1;j++){
// cout<<dw[i][j][0][0]<<" "<<dw[i][j][0][1]<<" ";
// }
// puts("");
// for(int j=0;j<=1;j++){
// cout<<dw[i][j][1][0]<<" "<<dw[i][j][1][1]<<" ";
// }
// puts("");
// }while(q--){int u,v;cin>>u>>v;if(u==v){cout<<"0\n";continue;}juz resu,resv;bool flu=0,flv=0;if(dep[u]>dep[v]){int ddep=dep[u]-dep[v],tmp=0;while(ddep){if(ddep&1){if(!flu){resu=up[u][tmp];flu=1;}else{resu=resu*up[u][tmp];}u=anc[u][tmp];}ddep>>=1,tmp++;}if(u==v){cout<<min(resu[0][0],resu[0][1])<<"\n";continue;}}else{int ddep=dep[v]-dep[u],tmp=0;while(ddep){if(ddep&1){if(!flv){resv=dw[v][tmp];flv=1;}else{resv=dw[v][tmp]*resv;}v=anc[v][tmp];}ddep>>=1,tmp++;}if(u==v){cout<<min(resv[0][0],resv[0][1])<<"\n";continue;}}
// for(int i=0;i<=1;i++){
// for(int j=0;j<=1;j++){
// cout<<resu[i][j]<<" ";
// }
// puts("");
// }
// for(int i=0;i<=1;i++){
// for(int j=0;j<=1;j++){
// cout<<resv[i][j]<<" ";
// }
// puts("");
// }for(int i=20;~i;i--){if(anc[u][i]!=anc[v][i]){if(!flu){resu=up[u][i];flu=1;}else{resu=resu*up[u][i];}if(!flv){resv=dw[v][i];flv=1;}else{resv=dw[v][i]*resv;}u=anc[u][i],v=anc[v][i];}}if(!flu){resu=up[u][0];}else{resu=resu*up[u][0];}if(!flv){resv=dw[v][0];}else{resv=dw[v][0]*resv;}juz res=resu*resv;cout<<min(res[0][0],res[0][1])<<"\n";}return 0;
}
}
int main(){return asbt::main();}