Gym 100685 G Gadget Hackwrench LCA+DFS标记

9 篇文章 0 订阅
6 篇文章 0 订阅

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;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值