2019.01.17【CodeForces757】F. Team Rocket Rises Again(最短路)(支配树)

版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/86521277

传送门


解析:

题意:给出一个有向图,求删除一个节点后,最多可能有多少个从 S S 开始的最短路边长(删除的节点距离变为INF)(不可以删除S)

思路:

支配树裸题。

显然删除的点要在 S S 到其他点的最短路上,而且是必经点。

跑一个最短路,构建出以 S S 为根的最短路DAG,然后Lengauer-Tarjan一波求出支配树。选择 S S 最大的儿子,就完了。。。

当然DAG有常数较小的做法,不过在允许边权为 0 0 的情况最短路DAG就不存在了。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define pc put_char
#define cs const

namespace IO{
	namespace IOONLY{
		cs int Rlen=1<<20|1;
		char buf[Rlen],*p1,*p2;
	}
	inline char get_char(){
		using namespace IOONLY;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	
	inline int getint(){
		re int num;
		re char c;
		while(!isdigit(c=gc()));num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return num;
	}
}
using namespace IO;

cs int N=200005;
int n,m;

vector<int> edge[N];
vector<int> w[N];

inline void addedge(int u,int v,int val){
	edge[u].push_back(v);
	edge[v].push_back(u);
	w[u].push_back(val);
	w[v].push_back(val);
}

ll dist[N];
set<pair<ll,int> > q;
int S;

inline void Dij(){
	memset(dist,0x3f,sizeof dist);
	dist[S]=0;
	q.insert(make_pair(0ll,S));
	while(!q.empty()){
		int u=q.begin()->second;
		q.erase(q.begin());
		for(int re e=0,v;e<edge[u].size();++e){
			v=edge[u][e];
			if(dist[v]>dist[u]+w[u][e]){
				q.erase(make_pair(dist[v],v));
				dist[v]=dist[u]+w[u][e];
				q.insert(make_pair(dist[v],v));
			}
		}
	}
}

vector<int> g[N],revg[N],dt[N];

inline void build(){
	Dij();
	for(int re u=1;u<=n;++u){
		for(int re e=0,v;e<edge[u].size();++e){
			v=edge[u][e];
			if(dist[v]==dist[u]+w[u][e]){
				g[u].push_back(v);
				revg[v].push_back(u);
			}
		}
	}
}

stack<int,vector<int> > dom[N];

int fa[N],dfn[N],id[N],dfs_clock;
void dfs(int u){
	id[dfn[u]=++dfs_clock]=u;
	for(int re e=0,v;e<g[u].size();++e){
		v=g[u][e];
		if(dfn[v])continue;
		fa[v]=u;dfs(v);
	}
}

int bel[N],semi[N],idom[N],nd[N];

inline int getfa(int x){
	if(bel[x]==x)return x;
	int tmp=getfa(bel[x]);
	if(dfn[semi[nd[bel[x]]]]<dfn[semi[nd[x]]])nd[x]=nd[bel[x]];
	return bel[x]=tmp;
}

inline void tarjan(){
	for(int re i=dfs_clock,u;i>1;--i){
		u=id[i];
		for(int re e=0,v;e<revg[u].size();++e){
			v=revg[u][e];
			if(!dfn[v])continue;
			getfa(v);
			if(dfn[semi[nd[v]]]<dfn[semi[u]])semi[u]=semi[nd[v]];
		}
		dom[semi[u]].push(u);
		u=bel[u]=fa[u];
		while(dom[u].size()){
			int v=dom[u].top();dom[u].pop();
			getfa(v);
			if(semi[nd[v]]==u)idom[v]=u;
			else idom[v]=nd[v];
		}
	}
	for(int re i=2,u;i<=dfs_clock;++i){
		u=id[i];
		if(semi[u]^idom[u])idom[u]=idom[idom[u]];
		dt[idom[u]].push_back(u);
	}
}

int siz[N];
void dfs_dt(int u){
	siz[u]=1;
	for(int re e=0,v;e<dt[u].size();++e){
		v=dt[u][e];
		dfs_dt(v);
		siz[u]+=siz[v];
	}
}

signed main(){
	n=getint(),m=getint(),S=getint();
	for(int re i=1;i<=m;++i){
		int u=getint(),v=getint(),val=getint();
		addedge(u,v,val);
	}
	
	for(int re i=1;i<=n;++i)semi[i]=nd[i]=bel[i]=i;
	build();
	dfs(S);
	tarjan();
	dfs_dt(S);
	int ans=0;
	for(int re e=0;e<dt[S].size();++e){
		ans=max(ans,siz[dt[S][e]]);
	}
	cout<<ans<<endl;
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/86521277
今日推荐