您的位置:首页 > 其它

hdu 4674 (缩点 + 倍增LCA)

2013-08-15 09:07 309 查看
题目链接

当时看到这道题目有点想法后来看到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
, out
;

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
;
	int pa
[lim], dep
, dis
;
	bool vis
;
	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
;
	int pre
, low
, no
;
	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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: