ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF1140G-Double Tree【最短路,矩阵乘法,树上倍增】

2022-07-12 12:04:03  阅读:145  来源: 互联网

标签:CF1140G const Double ll Tree leq 树上 include 短路


正题

题目链接:https://www.luogu.com.cn/problem/CF1140G


题目大意

给出一个\(n\)个点的树\(T\),然后复制一份\(T'\),每个\(T\)中的点\(i\)向\(T'\)中的点\(i\)都有连边构成一张图。

图上所有权值各不相同,现在\(q\)次询问图上两点的最短路。

\(1\leq n\leq 3\times 10^5,1\leq q\leq 6\times 10^5\)


解题思路

因为树上两点简单路径唯一,所以\(x\)到\(y\)之间的最短路肯定是包括两棵树中\(x\sim y\)路径上的某些点的。

现在问题就是从\(x\)到\(x'\)的切换问题,我们直接用最短路求出每个\(x\)到\(x'\)的最短距离,因为这样的距离肯定是在树上找一条点\(y\),\(x\)走到点\(y\)再从\(y'\)走回\(x'\)。

然后设\(f_{i,j,p,q}\)表示从点\(i\)出发往上跳了\(2^j\)步且原来在第\(p\)棵树上,现在在第\(k\)棵树上的方案。发现这个转移可以用矩阵乘法来优化。

然后求答案的时候找\(LCA\)的时候合并\(f\)矩阵就好了。

时间复杂度:\(O((n+q)\log n)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define ll long long
#define mp(x,y) make_pair(x,y)
using namespace std;
const ll N=3e5+10,T=21,S=2;
struct edge{
	ll to,next,u,v;
}a[N<<1];
struct node{
	ll a[S][S];
}c,one,G[N][T];
ll n,Q,tot,ls[N],f[N],dep[N],g[N][T];
bool v[N];
priority_queue<pair<ll,ll> > q;
node operator*(const node &a,const node &b){
	memset(c.a,0x3f,sizeof(c.a));
	for(ll i=0;i<S;i++)
		for(ll j=0;j<S;j++)
			for(ll k=0;k<S;k++)
				c.a[i][j]=min(c.a[i][j],a.a[i][k]+b.a[k][j]);
	return c;
}
void addl(ll x,ll y,ll u,ll v){
	a[++tot].to=y;
	a[tot].next=ls[x];ls[x]=tot;
	a[tot].u=u;a[tot].v=v;
	return;
}
void dij(){
	for(ll i=1;i<=n;i++)q.push(mp(-f[i],i));
	while(!q.empty()){
		ll x=q.top().second;q.pop();
		if(v[x])continue;v[x]=1;
		for(ll i=ls[x];i;i=a[i].next){
			ll y=a[i].to;
			if(f[x]+a[i].u+a[i].v<f[y]){
				f[y]=f[x]+a[i].u+a[i].v;
				q.push(mp(-f[y],y));
			}
		}
	}
	return;
}
void dfs(ll x,ll fa){
	dep[x]=dep[fa]+1;
	for(ll i=ls[x];i;i=a[i].next){
		ll y=a[i].to;
		if(y==fa)continue;
		dfs(y,x);g[y][0]=x;
		G[y][0].a[0][0]=min(a[i].u,f[x]+f[y]+a[i].v);
		G[y][0].a[1][1]=min(a[i].v,f[x]+f[y]+a[i].u);
		G[y][0].a[0][1]=min(a[i].u+f[x],a[i].v+f[y]);
		G[y][0].a[1][0]=min(a[i].v+f[x],a[i].u+f[y]);
	}
	return;
}
node Ask(ll x,ll y){
	node X=one,Y=one;bool flag=0;
	if(x==y){X.a[0][0]=X.a[1][1]=0;X.a[0][1]=X.a[1][0]=f[x];return X;}
	if(dep[x]<dep[y])swap(x,y),flag=1;
	for(ll i=T-1;i>=0;i--)
		if(dep[g[x][i]]>=dep[y])
			X=X*G[x][i],x=g[x][i];
	if(x==y){
		if(flag)swap(X.a[0][1],X.a[1][0]);
		return X;
	}
	for(ll i=T-1;i>=0;i--)
		if(g[x][i]!=g[y][i])
			X=X*G[x][i],x=g[x][i],
			Y=Y*G[y][i],y=g[y][i];
	X=X*G[x][0];Y=Y*G[y][0];
	swap(Y.a[0][1],Y.a[1][0]);
	X=X*Y;if(flag)swap(X.a[0][1],X.a[1][0]);
	return X;
}
signed main()
{
	memset(one.a,0x3f,sizeof(one.a));
	one.a[0][0]=one.a[1][1]=0;
	scanf("%lld",&n);
	for(ll i=1;i<=n;i++)
		scanf("%lld",&f[i]);
	for(ll i=1,x,y,u,v;i<n;i++){
		scanf("%lld%lld%lld%lld",&x,&y,&u,&v);
		addl(x,y,u,v);addl(y,x,u,v);
	}
	dij();dfs(1,0);
	for(ll j=1;j<T;j++)
		for(ll i=1;i<=n;i++){
			g[i][j]=g[g[i][j-1]][j-1];
			G[i][j]=G[i][j-1]*G[g[i][j-1]][j-1];
		}
	scanf("%lld",&Q);
	while(Q--){
		ll x,y;
		scanf("%lld%lld",&x,&y);
		node tmp=Ask((x+1)/2,(y+1)/2);
		printf("%lld\n",tmp.a[!(x&1)][!(y&1)]);
	}
	return 0;
}

标签:CF1140G,const,Double,ll,Tree,leq,树上,include,短路
来源: https://www.cnblogs.com/QuantAsk/p/16469579.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有