제출 #5432

#제출 시각아이디문제언어결과실행 시간메모리
5432Qwaz특수한 그래프 (IZhO13_specialg)C++98
100 / 100
84 ms22192 KiB
#include <cstdio>
#include <cmath>
#include <vector>

using namespace std;
const int MAX = 100020, BIT_MAX = 17;

int n, to[MAX], numQuery, qType[MAX], qA[MAX], qB[MAX];
vector < int > children[MAX];

void input(){
	scanf("%d", &n);

	int i;
	for(i = 1; i<=n; i++){
		scanf("%d", &to[i]);
		children[to[i]].push_back(i);
	}

	scanf("%d", &numQuery);
	for(i = 0; i<numQuery; i++){
		scanf("%d%d", &qType[i], &qA[i]);
		if(qType[i] == 2) scanf("%d", &qB[i]);
	}
}

int visited[MAX], cFull, cycleNum[MAX], cycleOrder[MAX], cycleSize[MAX];

int findCycle(int now, int visitNum){
	visited[now] = visitNum;

	if(visited[to[now]] == 0){
		int t = findCycle(to[now], visitNum);

		if(t != -1){
			cycleNum[now] = cFull;
			cycleOrder[now] = cycleOrder[to[now]]+1;
		} else {
			cycleNum[now] = -abs(cycleNum[to[now]]);
			cycleOrder[now] = cycleOrder[to[now]];
		}

		if(now == t) return -1;
		else return t;
	} else if(visited[to[now]] == visitNum){
		cycleNum[now] = ++cFull;
		cycleOrder[now] = 1;

		return to[now] == now ? -1 : to[now];
	} else {
		cycleNum[now] = -abs(cycleNum[to[now]]);
		cycleOrder[now] = cycleOrder[to[now]];
		return -1;
	}
}

int depth[MAX], p[20][MAX];

void calcDepth(int now){
	int i;
	for(i = 0; i<children[now].size(); i++){
		int nextNum = children[now][i];
		depth[nextNum] = depth[now]+1;
		calcDepth(nextNum);
	}
}

void init(){
	int i, v = 1;
	for(i = 1; i<=n; i++){
		if(visited[i] == 0)
			findCycle(i, v++);
	}

	for(i = 1; i<=n; i++){
		if(cycleNum[i] < 0){
			if(cycleNum[to[i]] == cycleNum[i]) p[0][i] = to[i];
			else {
				p[0][i] = i;
				depth[i] = 1;
				calcDepth(i);
			}
		} else {
			cycleSize[cycleNum[i]]++;
			p[0][i] = i;
		}
	}

	int lvl = 1;
	for(lvl = 1; lvl<=BIT_MAX; lvl++){
		for(i = 1; i<=n; i++)
			p[lvl][i] = p[lvl-1][p[lvl-1][i]];
	}
}

int uf[MAX], firstCut[MAX];
bool cycleOK[MAX];

int getParent(int num){
	if(uf[num] == num) return num;
	return uf[num] = getParent(uf[num]);
}

void link(int a, int b){
	if(getParent(a) == getParent(b)){
		cycleOK[cycleNum[a]] = 1;
	} else {
		uf[getParent(a)] = getParent(b);
	}
}

void cut(){
	int i, tNext[MAX];
	for(i = 1; i<=n; i++){
		tNext[i] = to[i];
		uf[i] = i;
	}

	for(i = 0; i<numQuery; i++){
		if(qType[i] == 1){
			int cn = cycleNum[qA[i]];
			if(cn > 0 && firstCut[cn] == 0){
				firstCut[cn] = cycleOrder[qA[i]];
			}
			tNext[qA[i]] = 0;
		}
	}

	for(i = 1; i<=n; i++){
		if(tNext[i]){
			link(i, tNext[i]);
		}
	}
}

int cycleDist(int f, int s){
	int cn = cycleNum[f];
	if(f == s || cycleOK[cn] ||
	   (cycleOrder[f] > cycleOrder[s]
	   ? !(cycleOrder[f] >= firstCut[cn] && firstCut[cn] > cycleOrder[s])
	   : !(cycleOrder[f] >= firstCut[cn] || firstCut[cn] > cycleOrder[s]))){
		int cs = cycleSize[cn];
		return (cycleOrder[f]-cycleOrder[s]+cs) % cs;
	} else return -1;
}

int res[MAX];

void solve(){
	int i;
	for(i = numQuery-1; i>=0; i--){
		if(qType[i] == 1){
			link(qA[i], to[qA[i]]);
		} else {
			res[i] = -1;

			int f = qA[i], s = qB[i];
			if(getParent(f) == getParent(s)){
				if(cycleNum[s] > 0){
					if(cycleNum[f] == cycleNum[s]){
						//사이클 -> 사이클
						res[i] = cycleDist(f, s);
					} else if(cycleNum[f] == -cycleNum[s]){
						//트리 -> 사이클
						int t = cycleDist(to[p[BIT_MAX][f]], s);
						if(t != -1)
							res[i] = depth[f]+t;
					}
				} else {
					if(cycleNum[f] == cycleNum[s] && cycleOrder[f] == cycleOrder[s] && depth[s] < depth[f]){
						//트리 -> 트리
						int dist = depth[f]-depth[s];

						int t;
						for(t = 0; t<=BIT_MAX; t++){
							if(dist & (1<<t)){
								f = p[t][f];
							}
						}

						if(f == s)
							res[i] = dist;
					}
				}
			}
		}
	}

	for(i = 0; i<numQuery; i++){
		if(qType[i] == 2){
			printf("%d\n", res[i]);
		}
	}
}

int main(){
	input();

	init();
	cut();

	solve();

	return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...