ICode9

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

【玛丽卡】【题解】

2022-04-10 12:02:51  阅读:106  来源: 互联网

标签:ch 路上 int 题解 短路 玛丽 fa 枚举


题目

给定N个点,M条边的无向图,N<=1000,M<=N*(N-1)/2。求1N的最短路中把任意一条边删去后,1N新的最短路长度的最大值。

Solution

一种暴力是先把最短路求出后,枚举每条边,将其删去,再重新跑最短路,用不加优化dij,复杂度O(N^3)
发现很难删去一条边,并很快的维护出新的最短路。
考虑枚举新的最短路的边,并寻找原最短路上有哪些边可以被其替代。
发现可以被替代的边一定是是最短路上连续的一段,因此可以用线段树维护区间取min。
如何求解新最短路的长度?
该边的长度+从起点到某端点的长度+从终点到另一端点的长度。后两个可以通过两遍dij求出。
注意实际枚举的是有向边,有可能会出现新最短路对应原最短路上为一个点的情况,此时要特判。
如何求线段树维护的区间端点?
先将原最短路的边编号,对于每个最短路上的点维护向1和向n的边的编号。
而且求解最短路的过程构成一个树,表示子节点的值又父节点转移过来。
记录每的点的fa,对于枚举的边的端点,一直跳fa,直到为最短路上的点,这个过程可以用并查集优化,预先把最短路上的fa设为自己,其余路径压缩。

Code

#include<bits/stdc++.h>
using namespace std;
//#define int long long
inline int read()
{
	int x=0,w=1;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if(ch=='-') {w=-1;ch=getchar();}
	while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	return x*w;
}
inline void write(int x)
{
	if(x<0) putchar('-'),x=~(x-1);
	if(x>9) write(x/10);
	putchar('0'+x%10);
}
const int N=1010,inf=0x3f3f3f3f;
int n,a[N][N],d[2][N],fa[2][N],id[2][N],vis[N],v[N][N];
struct node{
	int l,r,minn,tag;
}t[N<<2];
int s,m;
void dij(int p)
{
	d[p][s]=0;
	fa[p][s]=s;
	memset(vis,0,sizeof vis);
	for(int i=1;i<n;++i)
	{
		int x=0;
		for(int j=1;j<=n;++j){
			if(vis[j]) continue;
			if(x==0||d[p][j]<d[p][x]) x=j;
		}
		vis[x]=1;
		for(int j=1;j<=n;++j) {
			if(d[p][j]>d[p][x]+a[x][j]) d[p][j]=d[p][x]+a[x][j],fa[p][j]=x;
		}
	}
}
int find(int p,int x)
{
	return fa[p][x]==x?x:fa[p][x]=find(p,fa[p][x]);
}
void build(int x,int l,int r)
{
	t[x].l=l,t[x].r=r,t[x].minn=t[x].tag=inf;
	if(l==r) return ;
	int mid=l+r>>1;
	build(x<<1,l,mid);build(x<<1|1,mid+1,r);
}
void pushdown(int x)
{
	if(t[x].tag!=inf) 
	{
		int c=t[x].tag;t[x].tag=inf;
		t[x<<1].tag=min(t[x<<1].tag,c);
		t[x<<1|1].tag=min(t[x<<1|1].tag,c);
		t[x<<1].minn=min(t[x<<1].minn,c);
		t[x<<1|1].minn=min(t[x<<1|1].minn,c);
	}
}
void change(int x,int l,int r,int c)
{
	t[x].minn=min(t[x].minn,c);
	if(t[x].l>=l&&t[x].r<=r){
		t[x].tag=min(t[x].tag,c);
		return;
	}
	pushdown(x);
	int mid=t[x].l+t[x].r>>1;
	if(l<=mid) change(x<<1,l,r,c);
	if(r>mid) change(x<<1|1,l,r,c);
}
int query(int x,int pos)
{
	if(t[x].l==t[x].r) return t[x].minn;
	pushdown(x);
	int mid=t[x].l+t[x].r>>1;
	if(pos<=mid) return query(x<<1,pos);
	return query(x<<1|1,pos);
}
signed main()
{
    n=read();m=read();
    memset(d,0x3f,sizeof d);memset(a,0x3f,sizeof a);
    for(int i=1;i<=m;++i) 
    {
    	int x=read(),y=read(),z=read();
    	a[x][y]=a[y][x]=min(a[x][y],z);
	}
	s=1;dij(0);
	s=n;dij(1);
	int cnt=0;
	for(int i=n;fa[0][i]!=i;i=fa[0][i])
	{
		id[1][i]=id[0][fa[0][i]]=++cnt;
		fa[1][fa[0][i]]=fa[0][i];
		v[i][fa[0][i]]=v[fa[0][i]][i]=1;
	}
	build(1,1,cnt);
	for(int i=1;i<=n;++i) if(fa[1][i]==i) fa[0][i]=i;
	for(int i=1;i<=n;++i)
	{
		for(int j=1;j<=n;++j)
		{
			if(i==j||v[i][j]||a[i][j]==a[0][0]) continue;
			int u=find(0,i),v=find(1,j);
			if(id[1][v]&&id[1][v]<=id[0][u])
			change(1,id[1][v],id[0][u],a[i][j]+d[0][i]+d[1][j]);
		}
	}
	int ans=0;
	for(int i=1;i<=cnt;++i) ans=max(ans,query(1,i));
	write(ans);
	return 0;
}
/*
5 7
1 2 8
1 4 10
2 3 9
2 4 10
2 5 1
3 4 7
3 5 10
*/
/*
5 7
1 2 8
1 5 3
1 4 5
2 3 2
2 4 3
2 5 9
3 4 7
*/

标签:ch,路上,int,题解,短路,玛丽,fa,枚举
来源: https://www.cnblogs.com/glq-Blog/p/16125237.html

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

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

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

ICode9版权所有