对目前题解代码的借鉴和改良
查看原帖
对目前题解代码的借鉴和改良
224443
pp_orange楼主2024/1/16 16:07

小小改良,不发题解区了,可是看见题解区两篇几乎完全一样的代码感到非常疑惑。(难道那个是tarjan本人的论文实现?)

/* Code by pp_orange */
#include<bits/stdc++.h>
#define pb push_back
#define repp(i,l,r) for(int i=l;i<=r;++i)
#define pper(i,r,l) for(int i=r;i>=l;--i)
//#define int ll
const int intsz = sizeof(int);
using namespace std;
inline int rd(){
	int x(0),f(1);char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
	while (isdigit(ch)){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
	return x*f;
}
#define MAX 200005
vector<int> v[MAX];
vector<int> iv[MAX];//反图
vector<int> rechk[MAX];
array<int,3> pa[MAX];//<fa,mn,which> , 并查集
int tpa[MAX];// 树上父亲
int ord[MAX];
int dfn[MAX];
int sdom[MAX],idom[MAX];
int sz[MAX];
int tot = 0;
array<int,3> mrg(array<int,3> x,array<int,3> y){// x,y 有顺序,y是x祖先
	array<int,3> rlt;
	rlt[0] = y[0];
	if(y[1]<=x[1])rlt[1] = y[1],rlt[2] = y[2];
	// 必须是 <= ,这样我强制钦定是最上面的,和第62行的rechk和初始化搭配使用
	else rlt[1] = x[1],rlt[2] = x[2];
	return rlt;
}
array<int,3> fd(int x){//并查集
	if(x==pa[x][0])return pa[x];
	return pa[x] = mrg(pa[x],fd(pa[x][0]));
}
void dfs(int x,int fa){
	tpa[x] = fa;
	ord[dfn[x] = ++tot] = x;
	for(auto to:v[x])if(!dfn[to])dfs(to,x);
	return ;
}
signed main(){
	int n = rd();
	int m = rd();
	repp(i,1,m){
		int x = rd(),y = rd();
		v[x].pb(y);
		iv[y].pb(x);
	}
	sz[1] = 1;idom[1] = 1;
	dfs(1,1);
	repp(i,1,n)pa[i] = {i,dfn[i],i},sdom[i] = dfn[i];
	pper(i,tot,2){
		int nw = ord[i];
		for(auto to:rechk[nw])idom[to] = fd(to)[2];// 在父节点统一重新检测,题解里面都是边跑边重检测父亲,还要清空,非常麻烦
		for(auto to:iv[nw]){
			if(!dfn[to])continue;
			sdom[nw] = min(sdom[nw],fd(to)[1]);
		}
		pa[nw][0] = tpa[nw];pa[nw][1] = sdom[nw];
		idom[nw] = sdom[nw] = ord[sdom[nw]];
		rechk[sdom[nw]].pb(nw);
	}
	repp(i,2,tot){
		int nw=ord[i];
		if(sdom[nw]!=idom[nw])idom[nw] = idom[idom[nw]];
	}
	pper(i,tot,2){
		int nw=ord[i];
		sz[idom[nw]] += ++sz[nw];
	}
	repp(i,1,n)cout<<sz[i]<<' ';cout<<endl;
	return 0;
}

注释写代码了,我个人认为这样写边界少很多,也没有特别多的数组嵌套,代码也比较短。

2024/1/16 16:07
加载中...