wa两个点,有详细的注释,求调
查看原帖
wa两个点,有详细的注释,求调
819682
Exile_Code楼主2024/4/10 16:52
#define  _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include <vector>
#include <set>
#include <map>
#include <cstdio>
#include <cstring>
#include <queue>
#include <cstdlib>
#include <algorithm>
#include <list>
#include <string>
#include <cmath>
#include <bitset>
#include <stack>
#include <math.h>
#include <functional>

#define endl            '\n'
#define ull             unsigned long long 
#define ll              long long 
#define pii             pair<ll ,ll>
#define cy              cout<<"YES"<<'\n'
#define cn              cout<<"NO"<<'\n'
#define forn(i,begin,end,add)	for(ll (i)=(begin);(i)<=(end);(i)+=(add))	//begin是i的起始,end是i的终止,add是每次加的大小
#define rforn(i,begin,end,sub)  for(ll (i)=(end);(i)>=(begin);(i)-=(sub))	//r是倒序遍历
#define vv              vector
#define inf32           INT32_MAX/2
#define inf64           INT64_MAX/4
#define LD              long double
#define PI              acos(-1)
#define debug(a,b)		cout<<a<<b
#define eps				1e-12
const int N = 1e5 + 100;
const int mod = 998244353;
ll T;

vv<vv<ll>>e(N + 1);
vv<ll>instk(N);
vv<ll>dfn(N);
vv<ll>low(N);
vv<ll>siz(N);
vv<ll>scc(N);
stack<ll>st;
int cnt = 0, tot = 0;
vv<ll>all(N);

void tarjan(int x) {
	dfn[x] = low[x] = ++tot;
	st.push(x), instk[x] = true;
	for (int y : e[x]) {
		//if(y==x) 出现自环
		if (!dfn[y]) {
			tarjan(y);
			low[x] = min(low[x], low[y]);
		}
		else if (instk[y]) {//y还没往下走,所以用dfn更新
			low[x] = min(low[x], dfn[y]);//其实用low也行,因为dfn=low=++tot
		}
		//如果一个点既不在栈中,又已经走过了,不需要再走了,因为横跨边无法更新任何东西
	}
	//离开x时,记录scc
	if (dfn[x] == low[x]) {
		int y; ++cnt;
		do {
			y = st.top(); st.pop();
			instk[y] = false;
			scc[y] = cnt;
			++siz[cnt];//强连通分量的大小
		} while (y != x);
	}
}
vv<vv<int>>re(N);//反向边的图
void dfs(int u,int sz) {//简单dp
	
	all[u] = sz;
	for (auto a : re[u])
		dfs(a, sz + 1);
}
void solve() {


    int n; cin >> n;
    forn(i, 1, n, 1){
        int a; cin >> a;
		e[i].push_back(a);
		if (a == i)//判断自环
			all[i] = 1;
	}

	forn(i, 1, n, 1)//正常tarjan
		if (!dfn[i])
			tarjan(i);

	forn(i, 1, n,1 ) {//反向建边
		for (auto a : e[i]) {
			int thi = scc[i];
			int tha = scc[a];
			if (thi != tha) {
				re[a].push_back(i);
			}
		}
	}
	forn(i, 1, n, 1) {
		if (siz[scc[i]] > 1)//如果是环上的点就进入
			dfs(i, siz[scc[i]]);
	}
	forn(i, 1, n, 1)
		cout << all[i] << endl;

}
int main() {


    std::ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    T = 1;
    //cin >> T;
    while (T--)
        solve();


    return 0;
}
2024/4/10 16:52
加载中...