hdu 4674 (縮點 + 倍增LCA)

題目鏈接


當時看到這道題目有點想法後來看到59交0AC, 就知道肯定有不少trick,賽後看了題解才知道原來有這麼多種情況。。。

其實所有的情況大致可以這麼劃分, u 和 v是否相同, u, v不同時, 設u所在環是cu, v所在環是cv, p所在環是cp, 根據

cu == cv再劃分出兩種cu != cv時再根據cu == cp || cp == cv再劃分出兩種情況, 基本就是這樣, 對於最後幾種情況

還有考慮出環的點和入環的點這個可以在dfs的過程中得到, 代碼很長很醜。。。。


#include <iostream>
#include <queue>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <ctime>
#include <algorithm>

using namespace std;

inline int readint() {
	char c = getchar();
	while (!isdigit(c)) c = getchar();

	int x = 0;
	while (isdigit(c)) {
		x = x * 10 + c - '0';
		c = getchar();
	}

	return x;
}

const int N = 100005;
const int M = N << 2;
const int lim = 17; // 2 ^ lim > N

int in[N], out[N];

struct Tree {

	struct Edge {
		int v, ou, ov;
		Edge* next;

		void init(int a, Edge* e, int b, int c) {
			v = a, ou = b, ov = c;
			next = e;
		}    
	};

	Edge E[M];
	Edge* it, * head[N];
	int pa[N][lim], dep[N], dis[N];
	bool vis[N];
	int n;

	void init(int n) {
		this->n = n;
		for (int i = 0; i < n; i++) {
			head[i] = 0, vis[i] = 0;
		}
		it = E;
	}

	void add(int u, int v, int ou, int ov) {
		it->init(v, head[u], ou, ov);
		head[u] = it++;
		it->init(u, head[v], ov, ou);
		head[v] = it++;
	}

	int lca(int u, int v) {
		if (dep[u] > dep[v]) swap(u, v);
		if (dep[u] < dep[v]) {
			int d = dep[v] - dep[u];
			for (int i = 0; i < lim; i++)
				if (d & (1 << i))
					v = pa[v][i];
		}
		if (u != v) {
			for (int i = lim - 1; i >= 0; i--)
				if (pa[u][i] != pa[v][i]) {
					u = pa[u][i];
					v = pa[v][i];
				}
			u = pa[u][0];
		}
		return u;
	}

	void dfs(int u, int fa) {
		pa[u][0] = fa;
		dep[u] = dep[fa] + 1;
		vis[u] = 1;
		for (int i = 1; (1 << i) < n; i++)
			pa[u][i] = pa[pa[u][i - 1]][i - 1];
		for (Edge* e = head[u]; e; e = e->next) {
			int v = e->v;
			if (!vis[v] && v != fa) {
				out[v] = e->ov, in[v] = e->ou;
				dfs(v, u);    
			}
		}    
	}

	int anc(int u, int d) {
		if (d < 0) return -1;
		if (d == 0) return u;
		int fa = u;
		for (int i = 0; (1 << i) < n; i++) {
			if (d & (1 << i)) {
				fa = pa[u][i];
				u = fa;
			}    
		}
		return fa;        
	}

	void run(int rt) {
		dep[rt] = -1;
		dfs(rt, rt);
	}

}T;

struct Graph {

	struct Edge {
		int v;
		bool iscut;
		Edge* next, * pair;

		void init(int a, Edge* e1, Edge* e2) {
			this->v = a, next = e1;
			pair = e2;
			iscut = 0;
		}
	};

	Edge E[M], * head[N];
	int pre[N], low[N], no[N];
	Edge* it;
	int n, id, tdfn;

	void init(int n) {
		this->n = n;
		for (int i = 0; i < n; i++) {
			head[i] = 0;
			pre[i] = 0;
		}
		it = E;
		tdfn = 1;
	}

	void add(int u, int v) {
		it->init(v, head[u], it + 1);
		head[u] = it++;
		it->init(u, head[v], it - 1);
		head[v] = it++;
	}

	int dfs(int u, int fa) {
		int lowu = pre[u] = tdfn++;
		for (Edge* e = head[u]; e; e = e->next) {
			int v = e->v;
			if (!pre[v]) {
				int lowv = dfs(v, u);
				lowu = min(lowv, lowu);
				if (lowv > pre[u]) {
					e->iscut = 1;
					e->pair->iscut = 1;
				}
			}
			else if(v != fa && pre[v] < pre[u]) { 
				lowu = min(lowu, pre[v]);
			}
		}
		low[u] = lowu;
		return lowu;
	}

	void dfs(int u) {
		no[u] = id;
		for (Edge* e = head[u]; e; e = e->next) {
			if (e->iscut) continue;
			int v = e->v;
			if (no[v] == -1)
				dfs(v);    
		}
	}        

	void run() {
		dfs(0, -1);
		id = 0;
		for (int i = 0; i < n; i++) no[i] = -1;
		for (int i = 0; i < n; i++)
			if (no[i] == -1) {
				dfs(i);
				id++;
			}

		T.init(id);

		for (int u = 0; u < n; u++)
			for (Edge* e = head[u]; e; e = e->next) {
				int v = e->v;
				if (no[u] != no[v])
					T.add(no[u], no[v], u, v);    
			}

		T.run(0);

	}

	bool gao(int u, int v, int p) {
		if (u == v) {
			if (p == u) return 1;
			else return 0;
		}
		else {
			int tu = no[u], tv = no[v];
			int tp = no[p];
			if (tu == tv) {
				if (tp != tu) return 0;
				else return 1;
			}
			else {
				int fa = T.lca(tu, tv);
				if (tu == tp || tp == tv) {
					if (tu == tp) {
						if (fa != tu) {
							if (p != u && out[tu] == u)
								return 0;
							else
								return 1;        
						}
						else {
							int d = T.dep[tv] - T.dep[tu];
							int su = T.anc(tv, d - 1);
							if (p != u && in[su] == u)
								return 0;
							else
								return 1;    
						}    
					}
					else {
						if (fa != tv) {
							if (p != v && out[tv] == v)
								return 0;
							else
								return 1;        
						}
						else {
							int d = T.dep[tu] - T.dep[tv];
							int fu = T.anc(tu, d - 1);
							if (p != v && in[fu] == v)
								return 0;
							else
								return 1;        
						}    
					}    
				}
				else {
					int du = T.dep[tu] - T.dep[tp], dv = T.dep[tv] - T.dep[tp];
					int t1 = T.anc(tu, du - 1), t2 = T.anc(tv, dv - 1);


					if ((T.dep[tp] >= T.dep[fa]) && 
							((du > 0 && T.pa[t1][0] == tp) || (dv > 0 && T.pa[t2][0] == tp))) {
						if (tp == fa) {    
							if (in[t1] == in[t2] && in[t1] != p)
								return 0;
							else
								return 1;
						}
						else {
							if (T.pa[t1][0] == tp) {
								if (out[tp] == in[t1] && out[tp] != p)
									return 0;
								else
									return 1;    
							}
							else {
								if (out[tp] == in[t2] && out[tp] != p)
									return 0;
								else
									return 1;
							}
						}                    
					}
					else {
						return 0;
					}
				}    
			}

		}    
	}
}G;

int main() {
	int n, m, q, u, v, p;
	while (~scanf("%d", &n)) {
		m = readint();

		G.init(n);
		for (int i = 0; i < m; i++) {
			u = readint(), v = readint();
			u--, v--;
			G.add(u, v);
		}

		G.run();

		q = readint();

		for (int i = 0; i < q; i++) {
			u = readint(), v = readint(), p = readint();
			u--, v--, p--;
			if (G.gao(u, v, p))
				puts("Yes");
			else
				puts("No");
		}
	}    
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章