您的位置:首页 > 其它

Gym 100685 G Gadget Hackwrench LCA+DFS标记

2015-10-04 20:20 337 查看
G. Gadget Hackwrench

time limit per test
2 seconds

memory limit per test
64 megabytes

input
standard input

output
standard output

Chip 'n' Dale rescue rangers! But observant viewers know that help is usually required by Chip and Dale themselves. Today you are in the role of cunning Gadget Hackwrench.

So, Chip and Dale are again in the paws of Fat Cat. He doesn't like rodents much and therefore prepared a treacherous test. He is going to put them to a labyrinth and see if they can escape from it. The labyrinth is actually built as a tree where each edge
has fixed direction (by definition tree is a connected unoriented graph without cycles).

Gadget has intercepted a talk between Fat Cat and his henchmen about future tests. For each test round she knows the exact location where Chip and Dale are to be put by Fat Cat and the location of an exit. Gadget wants to compute whether they will be able to
find an exit for each test.

Input

The first line of input contains an integer N (1 ≤ N ≤ 105) —
the number of vertices in a graph.

On the next N - 1 lines of input directed arcs of the tree are given. On the (i + 1)th line
integer numbers ai and bi are
given (1 ≤ ai, bi ≤ N)
denoting an arc from vertex ai to
vertex bi.
It is guaranteed that arcs a1, a2, ..., an - 1 without
orientation form a tree.

Then a string with integer number M (1 ≤ M ≤ 105)
is given — the number of queries to process. Next M lines describe queries:(n + 1 + i)th line
contain integers xi and yi (1 ≤ xi, yi ≤ N).

Output

For each query please output a separate line containing 'Yes' (without quotes) if graph contains a path between xi and yi,
or 'No' (without quotes) in other case.

Sample test(s)

input
4
1 2
3 1
4 1
6
1 2
3 2
2 3
4 2
4 3
2 1


output
Yes
Yes
No
Yes
No
No


题目链接:http://codeforces.com/gym/100685/problem/G

题目大意:给定一张有向无环图,n个点,问从一点A到另外一点B是否存在一条通路可达。

思路:首先,以双向边的形式构建出LCA的st表,并标记正向边(flag = 0)与反向边(flag = 1)。然后,DFS一次,记录三项内容,分别是该节点所在深度cnt[],从该点沿正向走的最远距离dir_u[]和从该点沿反向走的最远距离dir_v[],于是,对于一组查询A和B,从A到B可达,当且仅当A到lca的距离不超过A的正向最远距离,同时B到lca的距离不超过B的反向最远距离。

AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#include <vector>
#include <limits.h>
#include <queue>
#include <map>
#include <set>
using namespace std;
typedef long long LL;
#define pll pair<LL, LL>
#define pii pair<int, int>
#define X first
#define Y second
#define MAXN 200010
#define lson l, mid, (rt << 1)
#define rson mid + 1, r, (rt << 1 | 1)
const double eps = 1e-10;
int head[MAXN];
int dp[MAXN][20], deep[MAXN];
int dir_u[MAXN], dir_v[MAXN], cnt[MAXN];
int totedge = 0, t, n, Q;
bool vis[MAXN];
struct node {
int to, next, flag;
} edge[MAXN << 1];
void init() {
totedge = 0;
memset(vis, false, sizeof vis);
memset(head, -1, sizeof head);
memset(dp, 0, sizeof dp);
memset(deep, 0, sizeof deep);
memset(dir_u, 0, sizeof dir_u);
memset(dir_v, 0, sizeof dir_v);
memset(cnt, 0, sizeof cnt);
}
void add(int from, int to, int flag) {
edge[totedge].to = to;
edge[totedge].next = head[from];
edge[totedge].flag = flag;
head[from] = totedge++;
}
void DFS(int u, int step) {
if(vis[u]) return ;
vis[u] = true;
if(step == 0) dp[u][0] = u;
deep[u] = step;
for(int i = 1; i < 20; i++)
dp[u][i] = dp[dp[u][i-1]][i-1];
for(int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].to;
if(vis[v]) continue;
dp[v][0] = u;
DFS(v, step + 1);
}
}
int LCA(int u, int v) {
if(deep[u] > deep[v]) swap(u, v);
int deep_len = deep[v] - deep[u];
int tu = u, tv = v;
for(int j = deep_len, i = 0; j ; j>>=1, i++) {
if(j & 1) tv = dp[tv][i];
}
if(tu == tv) return tu;
for(int i = 20 - 1; i >= 0; i--) {
if(dp[tu][i] == dp[tv][i]) continue;
tu = dp[tu][i], tv = dp[tv][i];
}
return dp[tu][0];
}
void DFS2(int u, int pre) {
for(int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].to;
if(v == pre) continue;
cnt[v] = cnt[u] + 1;
if(edge[i].flag == 0) {
dir_v[v] = dir_v[u] + 1;
dir_u[v] = 0;
} else {
dir_u[v] = dir_u[u] + 1;
dir_v[v] = 0;
}
DFS2(v, u);
}
}
int main() {
while(~scanf("%d", &n)) {
init();
int a, b;
for(int i = 0; i < n - 1; i++) {
scanf("%d%d", &a, &b);
add(a, b, 0);
add(b, a, 1);
}
DFS(1, 0);
scanf("%d", &Q);
DFS2(1, -1);
while(Q--) {
scanf("%d%d", &a, &b);
int lca = LCA(a, b);
int cnt1 = cnt[a] - cnt[lca];
int cnt2 = cnt[b] - cnt[lca];
if(cnt1 > dir_u[a] || cnt2 > dir_v[b]) {
puts("No");
} else puts("Yes");
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: