P1186 玛丽卡(最短路&线段树&并查集)

Posted Harris-H

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P1186 玛丽卡(最短路&线段树&并查集)相关的知识,希望对你有一定的参考价值。

P1186 玛丽卡(最短路&线段树&并查集)

题意:无向连通带权图,删掉一条边后所有最短路的最大值。

思路:

显然先跑一遍最短路,然后记录最短路的边,非最短路的边无影响,依次删除最短路的边跑最短路,时间复杂度: O ( n m l o g n ) O(nmlogn) O(nmlogn),会T。

考虑如何优化。

考虑强制用其他非最短路跑最短路,会替换掉最短路的哪些路径,将这些路径的贡献该为利用其他边跑最短路的最小值,这样就变成了一个区间修改问题。

然后查找路径的话,可以利用并查集,将最短路上的路径的fa都标记为自己,非最短路上的路径记为前驱,每次更新一段区间,然后对最短路的上每条边进行取最小值,然后所有单点取最大值。至于点到边的转换,可以将边映射到对应的右端点。

这样时间复杂度就是: O ( n 2 l o g n ) O(n^2logn) O(n2logn)了。

code

// Problem: P1186 玛丽卡
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P1186
// Memory Limit: 128 MB
// Time Limit: 1000 ms
// Date: 2021-07-05 09:07:43
// --------by Herio--------

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull; 
const int N=1e3+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define lx x<<1
#define rx x<<1|1
#define ios ios::sync_with_stdio(false),cin.tie(0) 
int n,m;
struct node{
	int l,r,mi,lz;
}a[N<<2];
int fa[N],g[N][N];
int d[2][N],vis[N];
int num[N],nn;
void build(int x,int l,int r){
	a[x].l=l,a[x].r=r,a[x].mi=a[x].lz=inf;
	if(l==r) return;
	int mid=l+r>>1;
	build(lx,l,mid);
	build(rx,mid+1,r);
}
void re(int x){
	a[x].mi=min(a[lx].mi,a[rx].mi);
}
void pushdown(int x){
	if(a[x].lz!=inf){
		a[lx].mi=min(a[lx].mi,a[x].lz);
		a[lx].lz=min(a[lx].lz,a[x].lz);
		a[rx].mi=min(a[rx].mi,a[x].lz);
		a[rx].lz=min(a[rx].lz,a[x].lz);
	}
	a[x].lz=inf;
}
void upd(int x,int l,int r,int v){
	if(a[x].l>=l&&a[x].r<=r){
		a[x].mi=min(a[x].mi,v);
		a[x].lz=min(a[x].lz,v);
		return;
	}
	int mid=a[x].l+a[x].r>>1;
	if(l<=mid) upd(lx,l,r,v);
	if(r>mid) upd(rx,l,r,v);
	re(x);
}
int que(int x,int v){
	if(a[x].l==a[x].r) return a[x].mi;
	pushdown(x);
	int mid=a[x].l+a[x].r>>1;
	if(v<=mid) return que(lx,v);
	else return que(rx,v);
}
int find(int x){
	return fa[x]==x?x:fa[x]=find(fa[x]);
}
void dij(int st,int fg){
	d[fg][st]=0;
	mst(vis,0);mst(fa,0);
	for(int i=1;i<=n;i++){
		int pos=0;
		for(int j=1;j<=n;j++)
			if(!vis[j]&&d[fg][j]<d[fg][pos]) pos=j;
		vis[pos]=1;
		for(int j=1;j<=n;j++)
			if(!vis[j]&&d[fg][j]>d[fg][pos]+g[pos][j]){
				d[fg][j]=d[fg][pos]+g[pos][j];
				fa[j]=pos;
			}
	}
}
int main(){
	scanf("%d%d",&n,&m);
	mst(g,0x3f);
	for(int i=1;i<=m;i++){
		int u,v,w;scanf("%d%d%d",&u,&v,&w);
		g[u][v]=g[v][u]=w;
	}
	mst(d,0x3f);
	dij(n,1);dij(1,0);
	for(int i=n;i;){
		int father=fa[i];
		g[i][father]=g[father][i]=inf;
		fa[i]=i;
		num[i]=++nn;
		i=father;
	}
	//for(int i=1;i<=n;i++) printf("%d ",fa[i]);printf("\\n");
	build(1,1,nn);
	for(int i=1;i<=n;i++)
		for(int j=i+1;j<=n;j++){
			if(g[i][j]==inf) continue;
			int u=find(i),v=find(j);
			if(u!=v){
				int ql=num[u],qr=num[v];
				if(ql>qr) swap(ql,qr);
				++ql;
				int v=min(d[0][i]+d[1][j]+g[i][j],d[1][i]+g[i][j]+d[0][j]);
				//printf("%d\\n",v);
				upd(1,ql,qr,v);
			}
		}
	int ans=0;
	for(int i=2;i<=nn;i++)
		ans=max(ans,que(1,i));
	printf("%d\\n",ans);
	return 0;
}

参考文章

https://www.luogu.com.cn/blog/nitubenben/p1186-ma-li-ka-ti-xie

以上是关于P1186 玛丽卡(最短路&线段树&并查集)的主要内容,如果未能解决你的问题,请参考以下文章

Luogu P1186 玛丽卡 最短路By cellur925

LUOGU P1186 玛丽卡

Luogu P1186 玛丽卡

P1186 玛丽卡

luogu P1186玛丽卡

P2176路障与P1186玛丽卡与P1491集合位置全面胜利