【题解】Luogu P7359 「JZOI-1」旅行

考虑一次询问,显然 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 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();}
posted @ 2025-02-09 09:42  zhangxy__hp  阅读(28)  评论(0)    收藏  举报