二分真的太好用了你知道吗
看到题目,发现要使最小值最大,考虑二分。
先以
对新图跑边双 tarjan,如果
最后判一下,如果
好处是不用写一堆特判,思维和代码难度双低,比线段树好想一万倍。
:::info[正确性]
下证新图
首先如果不连通,充分性显然。
然后,如果有割边,说明
必要性,考虑证明否命题,即
删边在最短路上,显然对于最短路上任意一条边都有不经过它的长度
证毕。
| 至于方案数, |
|---|
:::success[code]
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define llg long long
#define usg unsigned
#define ull unsigned long long
const int inf=1ll<<50;
vector<int>g[100005],f[100005];
int n,m,vis[100005];
struct node{
int id,vl;
bool operator <(const node &z)const{
return vl<z.vl;
}
bool operator >(const node &z)const{
return vl>z.vl;
}
};
priority_queue<node,vector<node>,greater<node> >q;
void dijk(int st,int *dis){
for(int i=1;i<=n;++i)dis[i]=inf,vis[i]=0;
q.push(node{st,0});
dis[st]=0;
while(q.size()){
node h=q.top();
q.pop();
if(vis[h.id])continue;
vis[h.id]=1;
for(int i=0;i<g[h.id].size();++i){
int u=g[h.id][i],v=f[h.id][i];
if(vis[u]||dis[u]<=h.vl+v)continue;
dis[u]=h.vl+v;
q.push(node{u,dis[u]});
}
}
}
int dis[2][100005];
vector<int>gg[100005];
int dft,dfn[100005],low[100005],scc,bl[100005];
stack<int>stk;
void dfs1(int x,int y){
dfn[x]=low[x]=++dft;
stk.push(x);
for(int i=0;i<gg[x].size();++i){
int u=gg[x][i];
if(u==y){
y=0;
continue;
}
if(!dfn[u]){
dfs1(u,x);
low[x]=min(low[x],low[u]);
}else if(!bl[u])low[x]=min(low[x],dfn[u]);
}
if(dfn[x]==low[x]){
++scc;
while(1){
int u=stk.top();
stk.pop();
bl[u]=scc;
if(u==x)break;
}
}
}
int dds[100005];
void dfs2(int x,int y){
dds[x]=y;
for(int i=0;i<gg[x].size();++i){
int u=gg[x][i];
if(~dds[u])continue;
if(bl[u]==bl[x])dfs2(u,y);
else dfs2(u,y+1);
}
}
int check(int x){
for(int i=1;i<=n;++i)gg[i].clear(),dds[i]=-1,dfn[i]=0,bl[i]=0;
dft=0;
scc=0;
for(int i=1;i<=n;++i){
for(int j=0;j<g[i].size();++j){
int u=g[i][j],v=f[i][j];
if(i<u){
if(dis[0][i]+v+dis[1][u]<=x||dis[0][u]+v+dis[1][i]<=x){
gg[i].push_back(u);
gg[u].push_back(i);
}
}
}
}
for(int i=1;i<=n;++i)if(!dfn[i])dfs1(i,0);
dfs2(1,0);
return dds[n]==-1?inf:dds[n];
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n>>m;
for(int i=1;i<=m;++i){
int x,y,z;
cin>>x>>y>>z;
g[x].push_back(y);
g[y].push_back(x);
f[x].push_back(z);
f[y].push_back(z);
}
dijk(1,dis[0]);
dijk(n,dis[1]);
int l=0,r=1<<30;
while(l<r){
int mid=l+r>>1;
if(check(mid))l=mid+1;
else r=mid;
}
cout<<l<<" ";
if(l==dis[0][n])cout<<m;
else cout<<check(l-1);
return 0;
}
:::