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 玛丽卡(最短路&线段树&并查集)的主要内容,如果未能解决你的问题,请参考以下文章