joisc2018_l 题解

joisc2018_l

思路

aiai+1 之间取最短路最优。但因为有不能折返的限制,所以希望对每对 u,v 找到 k 条最短路使得任意断掉 u 的一条出边和 v 的一条入边,uv 的最短路还在 k 条中。

先跳过这一部分。如果可以在可行复杂度内预处理出结构体 mnu,v,i 表示 uv 的第 i 条最短路的距离,最短路中 u 去向的点和去向 v 的点,怎么做。

考虑线段树维护每个间隔。记录 vi,j 表示间隔的区间 [l,r] 中,al\(a_{l+1\) 取第 i 条最短路,arar+1 取第 j 条最短路的区间最短路。合并时枚举左边区间的右端点状态和右边区间的左端点状态,复杂度 O(k4llogl)l105,所以希望 k 尽量小。

可以构造 k=4 条最短路。

  • uv 的最短路:u,uu,,vv,v

  • 不经过 uu,vv 的最短路:u,uu,,vv,v

  • 不经过 uu 且不同于 2 的最短路:u,u3/uu,,v3,v

  • 不经过 vv 且不同于 2 的最短路:u,u4,,v4/vv,v

现在要求两点间不过第三点的最短路。厉害的是,可以把无向边拆除两条有向边当成点跑的最短路。

从每条边 s 开始跑最短路,有 m 个点,degu2=m2 条边,复杂度 O(m3logm)。但有大量的边只会造成一次入队。设当前做到边 uu 指向点 uu,如果这是第一次到达点 uu,那么枚举除了边 u 的反向边以外的起点为 uu 的边转移,记录 lstuu=u;如果这是第二次到达点 uu,说明边形成一个环,可以转移到 lstuu 的反向边,并且转移到其他所有边都不会更优;如果大于 2 次,就不会有任何转移。这样做入队次数为 O(degu)=O(m),单次复杂度 O(mlogm)

然后枚举点 u 和出边 i,点 v 和出边 j,找到 4 条最短路。复杂度 O(degudegv)=O(m2)

总复杂度 O(m2logm+k4llogl)

code

int n,m,t,l;
int head[maxn],tot=1;
struct nd{
	int nxt,to,fr;ll w;
}e[maxn];
void add(int u,int v,ll w){e[++tot]={head[u],v,u,w};head[u]=tot;}
ll dis[maxn][maxn];
struct Dis{
	int id;ll dis;
	bool operator <(const Dis&tmp)const{return dis>tmp.dis;}
};
priority_queue<Dis> q;
bool vis[maxn];int bk[maxn];
void dij(int s){
	for(int i=2;i<=tot;i++)dis[s][i]=inf;
	memset(vis,0,sizeof(vis));memset(bk,0,sizeof(bk));
	dis[s][s]=e[s].w;q.push({s,dis[s][s]});
	// cout<<s<<"\n";
	while(!q.empty()){
		int u=q.top().id;q.pop();
		if(vis[u])continue;vis[u]=1;
		// cout<<u<<" "<<dis[s][u]<<"\n";
		if(bk[e[u].to]){
			if(dis[s][bk[e[u].to]]>dis[s][u]+e[bk[e[u].to]].w){
				dis[s][bk[e[u].to]]=dis[s][u]+e[bk[e[u].to]].w;
				q.push({bk[e[u].to],dis[s][bk[e[u].to]]});
			}
			bk[e[u].to]=-1;
		}
		if(!bk[e[u].to]){
			for(int i=head[e[u].to];i;i=e[i].nxt){
				int v=e[i].to;if(!bk[e[u].to]&&i==(u^1))continue;
				// cout<<v<<"\n";
				if(dis[s][i]>dis[s][u]+e[i].w){
					dis[s][i]=dis[s][u]+e[i].w;
					q.push({i,dis[s][i]});
				}
			}
			bk[e[u].to]=u^1;
		}
	}
}
int a[maxm];
struct path{
	ll dis;int x,y;
}mn[maxn][maxn][4];
path Min(path u,path v){if(u.dis<v.dis)return u;return v;}
struct mat{
	ll v[4][4];
	mat(){memset(v,0x3f,sizeof(v));}
}tree[maxm<<2];
mat merge(mat u,mat v,int mid){
	mat res;
	for(int i=0;i<4;i++){
		for(int j=0;j<4;j++){
			res.v[i][j]=inf;
			for(int k=0;k<4;k++){
				for(int l=0;l<4;l++){
					if(mn[a[mid]][a[mid+1]][k].y!=mn[a[mid+1]][a[mid+2]][l].x)res.v[i][j]=min(res.v[i][j],u.v[i][k]+v.v[l][j]);
				}
			}
		}
	}
	return res;
}
#define mid (l+r>>1)
#define ls nd<<1
#define rs nd<<1|1
void build(int nd,int l,int r){
	if(l==r){
		for(int i=0;i<4;i++)tree[nd].v[i][i]=mn[a[l]][a[l+1]][i].dis;
		return ;
	}
	build(ls,l,mid),build(rs,mid+1,r);
	tree[nd]=merge(tree[ls],tree[rs],mid);
}
void updata(int nd,int l,int r,int p){
	if(l==r){
		for(int i=0;i<4;i++)tree[nd].v[i][i]=mn[a[l]][a[l+1]][i].dis;
		return ;
	}
	if(p<=mid)updata(ls,l,mid,p);
	else updata(rs,mid+1,r,p);
	tree[nd]=merge(tree[ls],tree[rs],mid);
}
void work(){
	n=read();m=read();t=read();l=read();
	for(int i=1;i<=m;i++){
		int u=read(),v=read(),w=read();
		add(u,v,w),add(v,u,w);
	}
	for(int i=1;i<=l;i++)a[i]=read();
	for(int i=2;i<=tot;i++)dij(i);
	for(int u=1;u<=n;u++){
		for(int v=1;v<=n;v++)if(u!=v){
			for(int i=0;i<4;i++)mn[u][v][i]={inf,0,0};
			for(int i=head[u];i;i=e[i].nxt){
				int uu=e[i].to;
				for(int j=head[v];j;j=e[j].nxt){
					int vv=e[j].to;
					mn[u][v][0]=Min(mn[u][v][0],{dis[i][j^1],uu,vv});
				}
			}
			for(int i=head[u];i;i=e[i].nxt){
				int uu=e[i].to;
				for(int j=head[v];j;j=e[j].nxt){
					int vv=e[j].to;
					if(uu!=mn[u][v][0].x&&vv!=mn[u][v][0].y)mn[u][v][1]=Min(mn[u][v][1],{dis[i][j^1],uu,vv});
				}
			}
			for(int i=head[u];i;i=e[i].nxt){
				int uu=e[i].to;
				for(int j=head[v];j;j=e[j].nxt){
					int vv=e[j].to;
					if(uu!=mn[u][v][0].x&&vv!=mn[u][v][1].y)mn[u][v][2]=Min(mn[u][v][2],{dis[i][j^1],uu,vv});
				}
			}
			for(int i=head[u];i;i=e[i].nxt){
				int uu=e[i].to;
				for(int j=head[v];j;j=e[j].nxt){
					int vv=e[j].to;
					if(uu!=mn[u][v][1].x&&vv!=mn[u][v][0].y)mn[u][v][3]=Min(mn[u][v][3],{dis[i][j^1],uu,vv});
				}
			}
		}
	}
	build(1,1,l-1);
	while(t--){
		int u=read(),v=read();a[u]=v;
		if(u>1)updata(1,1,l-1,u-1);
		updata(1,1,l-1,u);
		ll ans=inf;for(int i=0;i<4;i++)for(int j=0;j<4;j++)ans=min(ans,tree[1].v[i][j]);
		if(ans>=inf)ans=-1;
		printf("%lld\n",ans);
	}
}
posted @   yhddd  阅读(12)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示