关于Tarjan中的手写栈和STL栈
查看原帖
关于Tarjan中的手写栈和STL栈
642173
light_dream楼主2024/9/17 17:43

问题:

为什么 Tarjan\text{Tarjan} 用手写栈就可以不开 O2\text{O2} 过,但是 STL\text{STL} 栈不开 O2\text{O2} 就过不了?

故事:

刚开始写这道题的时候,由于本人十分喜欢用 STL\text{STL} 而十分厌恶手写的栈,就用 STL\text{STL} 中栈写了一个 Tarjan\text{Tarjan},代码如下:

void Tarjan(int u){
	low[u]=dfn[u]=++tim;//初次访问
	st.push(u);
	vis[u]=true;
	for(int v:g[u]){
		if(dfn[v]==0){//不曾访问
			Tarjan(v);
			low[u]=min(low[u],low[v]);
		}
		else if(vis[v]){
			low[u]=min(low[u],low[v]);
		}
	}
	if(dfn[u]==low[u]){//自成一个强连通分量
		int v;
		do{
			p[u]+=p[v];
			v=st.top();
			st.pop();
			vis[v]=false;
			scc[v]=u;
		}while(u!=v);
	}
}

其中,pp 数组表示的是一个强连通分量的总点权,我用一个结点编号代表一个强连通分量,也即scc[u]==u的时候,uu 这个结点代表了一个强连通分量。

当时开着 O2\text{O2} 也是过去了,也没怎么在意。后来我二刷这道题的时候,发现不开 O2\text{O2} 这道题就过不去了,这怎么行呢?于是我调试了三天三夜也没调试出来,放弃了。这是完整代码:

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e4+10;
int n,m;
int low[MAXN],dfn[MAXN],tim=0;//dfn[i]表示初次访问i点的时间戳
bool vis[MAXN];
vector<int> g[MAXN];
stack<int> st;//访问到某个点u的时候,栈中存储u的祖先和已经访问过的可以到达u的祖先的点
int scc[MAXN];
int p[MAXN];//连通块的总点权
int in_d[MAXN];
queue<int> q;
int dis[MAXN];
struct EDGE{
	int startpoint;
	int endpoint;
}edge[(MAXN<<3)+(MAXN<<1)];
void Tarjan(int u){
	low[u]=dfn[u]=++tim;//初次访问
	st.push(u);
	vis[u]=true;
	for(int v:g[u]){
		if(dfn[v]==0){//不曾访问
			Tarjan(v);
			low[u]=min(low[u],low[v]);
		}
		else if(vis[v]){
			low[u]=min(low[u],low[v]);
		}
	}
	if(dfn[u]==low[u]){//自成一个强连通分量
		int v;
		do{
			p[u]+=p[v];
			v=st.top();
			st.pop();
			vis[v]=false;
			scc[v]=u;
		}while(u!=v);
	}
}
int tp(){
	for(int i=1;i<=n;++i){
		if(scc[i]==i&&in_d[i]==0){
			q.push(i);
			dis[i]=p[i];
		}
	}
	while(q.size()){
		int u=q.front();
		q.pop();
		for(int v:g[u]){
			dis[v]=max(dis[v],dis[u]+p[v]);
			--in_d[v];
			if(in_d[v]==0){
				q.push(v);
			}
		}
	}
	int ans=-1;
	for(int i=1;i<=n;++i){
		ans=max(ans,dis[i]);
	}
	return ans;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i){
		scanf("%d",&p[i]);
	}
	for(int i=1,u,v;i<=m;++i){
		scanf("%d%d",&u,&v);
		g[u].push_back(v);
		edge[i].startpoint=u;
		edge[i].endpoint=v;
	}
	for(int i=1;i<=n;++i){
		if(dfn[i]==0){
			Tarjan(i);
		}
	}
	for(int i=1;i<=n;++i){
		g[i].clear();
	}
	for(int i=1;i<=m;++i){
		int u=scc[edge[i].startpoint],v=scc[edge[i].endpoint];
		if(u!=v){
			g[u].push_back(v);
			++in_d[v];
		}
	}
	printf("%d\n",tp());
	return 0;
}

几天后我想到,没有一个 O2\text{O2} 和无 O2\text{O2}Tarjan\text{Tarjan} 板子怎么行呢?于是我被迫重写了一次 Tarjan\text{Tarjan},完整代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int MAXN=1e4+10;
int stk[MAXN],dfn[MAXN],low[MAXN],tp=0,tim=0;
bool vis[MAXN];
vector<int> g[MAXN];
int scc_cnt=0,scc[MAXN];
int n,m;
int in_d[MAXN];
int dis[MAXN],p[MAXN],f[MAXN];
queue<int> q;
struct EDGE{
	int startpoint;
	int endpoint;
}edge[(MAXN<<3)+(MAXN<<1)];
void Tarjan(int u){
	low[u]=dfn[u]=++tim;
	stk[++tp]=u;
	vis[u]=true;
	for(int v:g[u]){
		if(!dfn[v]){
			Tarjan(v);
			low[u]=min(low[u],low[v]);
		}
		else if(vis[v]){
			low[u]=min(low[u],low[v]);
		}
	}
	if(dfn[u]==low[u]){
		int v;
		++scc_cnt;
		do{
			v=stk[tp--];
			vis[v]=false;
			scc[v]=scc_cnt;
			p[scc_cnt]+=f[v];
		}while(u!=v);
	}
}
int Topo(){
	for(int i=1;i<=scc_cnt;++i){
		if(in_d[i]==0){
			q.push(i);
			dis[i]=p[i];
		}
	}
	while(q.size()){
		int u=q.front();
		q.pop();
		for(int v:g[u]){
			dis[v]=max(dis[v],dis[u]+p[v]);
			--in_d[v];
			if(in_d[v]==0){
				q.push(v);
			}
		}
	}
	int ans=0;
	for(int i=1;i<=scc_cnt;++i){
		ans=max(ans,dis[i]);
	}
	return ans;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i){
		scanf("%d",&f[i]);
	}
	for(int i=1,u,v;i<=m;++i){
		scanf("%d%d",&u,&v);
		g[u].push_back(v);
		edge[i].startpoint=u,edge[i].endpoint=v;
	}
	for(int i=1;i<=n;++i){
		if(!dfn[i]){
			Tarjan(i);
		}
	}
	for(int i=1;i<=n;++i){
		g[i].clear();
	}
	for(int i=1;i<=m;++i){
		int u=scc[edge[i].startpoint],v=scc[edge[i].endpoint];
		if(u!=v){
			g[u].push_back(v);
			++in_d[v];
		}
	}
	printf("%d",Topo());
}

然后发现无论有没有 O2\text{O2} 这份代码都能够过。

在此求助各位大佬,这是为什么?可以看到两份代码唯一的区别就是手写栈和 STL\text{STL} 栈。

2024/9/17 17:43
加载中...