【題解】Luogu P7359 「JZOI-1」旅行
考慮一次詢問(wèn),顯然 DP,設(shè) \(f_{u,0/1}\) 表示走路/坐船到 \(u\) 點(diǎn)的最小花費(fèi)即可。
多次詢問(wèn),考慮維護(hù)矩陣,廣義矩陣乘,倍增處理詢問(wèn)。比如對(duì)于一條順流的邊 \(i\),可以構(gòu)造矩陣:
\[\begin{bmatrix}
a_i&L+a_i-z_i\\
a_i&a_i-z_i
\end{bmatrix}
\]
對(duì)每個(gè)點(diǎn) \(u\) 維護(hù) \(up_{u,i}\) 和 \(dw_{u,i}\) 表示從 \(u\) 向上走到 \(2^i\) 級(jí)祖先的矩陣和從 \(2^i\) 級(jí)祖先向下走到 \(u\) 的矩陣。時(shí)間復(fù)雜度 \(O((N+T)\log N)\)。
#include<bits/stdc++.h>
#define ll long long
#define il inline
using 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();}

浙公網(wǎng)安備 33010602011771號(hào)