1. 程式人生 > 其它 >題解 SP11985 【GOT - Gao on a tree】

題解 SP11985 【GOT - Gao on a tree】

\(\Large\texttt{SP11985 GOT}\)

怎麼題解區還有樹剖啊?資料結構不至於。

推薦一種碼量極小的 \(\mathcal O(n)\) 的寫法。

前置知識:\(\texttt{Tarjan}\)\(\texttt{LCA}\) 的思想

思路

我們不需要資料結構,我們就用一些記錄顏色的桶,根據我們 Tarjan 求 LCA 的思路,在 DFS 遍歷的過程中,對於一個詢問,我們只需要比較它們在 DFS 過程中記錄的關於其詢問的資訊,就可以得出詢問的答案。

對於遍歷到一個點,我們可以(套路地)記錄這個點到根節點其詢問顏色的最深節點編號,對於一個詢問我們記錄兩個點的這種資訊,我們發現,如果這兩個點之間有我們要找的顏色的點,那麼這兩個點記錄的值必然是不同的,即必然有其中一個值屬於 \([LCA, x]\)

這段區間內而不屬於 \([LCA, y]\) 這段區間內。

對於查詢兩端的 LCA 這個節點,為了將它也統計進去,我們在記錄顏色最低節點的時候記錄為當前鏈種這個節點的兒子節點的編號,這樣 LCA 也能判到,最後特判下詢問的兩個端點就好了。

程式碼

口胡難懂,Code棒棒。

int a, b, d[N + 5], s[N + 5], ans[N + 5];
struct A {
	int o, d, c;
} ask[N + 5];
vector<int> st[N + 5], q[N + 5];

void dfs(int n, int fa) {
	int _d = d[s[fa]];
	d[s[fa]] = n;
	rep(i, 0, siz(q[n]) - 1) {
		int id = q[n][i];
		if (ask[id].o) ans[id] |= (d[ask[id].c] != ask[id].d);
		else {
			ask[id].o = 1;
			ask[id].d = d[ask[id].c];
		}
	}
	rep(i, 0, siz(st[n]) - 1) {
		int v = st[n][i];
		if (v == fa) continue;
		dfs(v, n);
	}
	d[s[fa]] = _d;
}

signed main() {
	// freopen("in1.in", "r", stdin);
	// freopen("out.out", "w", stdout);
	while (~scanf("%d%d", &a, &b)) {
		rep(i, 1, a) s[i] = read() + 1, st[i].clear();
		rep(i, 1, a + 1) q[i].clear();
		rep(i, 1, b) ask[i] = (A) {0, 0, 0};
		int x, y;
		rep(i, 1, a - 1) {
			x = read();
			y = read();
			st[x].PB(y);
			st[y].PB(x);
		}
		rep(i, 1, b) {
			x = read();
			y = read();
			ask[i].c = read() + 1;
			ans[i] = (s[x] == ask[i].c || s[y] == ask[i].c);
			q[x].PB(i);
			q[y].PB(i);
		}
		dfs(1, 0);
		rep(i, 1, b) puts(ans[i] ? "Find" : "NotFind");
		puts("");
	}
	return 0;
}