Blow up the city(HDU-6604)

Problem Description

Country A and B are at war. Country A needs to organize transport teams to deliver supplies toward some command center cities.

In order to ensure the delivery works efficiently, all the roads in country A work only one direction. Therefore, map of country A can be regarded as DAG( Directed Acyclic Graph ). Command center cities only received supplies and not send out supplies.

Intelligence agency of country B is credibly informed that there will be two cities carrying out a critical transporting task in country A. 

As long as **any** one of the two cities can not reach a command center city, the mission fails and country B will hold an enormous advantage. Therefore, country B plans to destroy one of the n cities in country A and all the roads directly connected. (If a city carrying out the task is also a command center city, it is possible to destroy the city to make the mission fail)

Now country B has made q hypotheses about the two cities carrying out the critical task.

Calculate the number of plan that makes the mission of country A fail.

Input

The first line contains a integer T (1≤T≤10), denoting the number of test cases.

In each test case, the first line are two integers n,m, denoting the number of cities and roads(1≤n≤100,000,1≤m≤200,000).
Then m lines follow, each with two integers u and v, which means there is a directed road from city u to v (1≤u,v≤n,u≠v).

The next line is a integer q, denoting the number of queries (1≤q≤100,000)

And then q lines follow, each with two integers a and b, which means the two cities carrying out the critical task are a and b (1≤a,b≤n,a≠b).

A city is a command center if and only if there is no road from it (its out degree is zero).

Output

For each query output a line with one integer, means the number of plan that makes the mission of country A fail.

Sample Input

2
8 8
1 2
3 4
3 5
4 6
4 7
5 7
6 8
7 8
2
1 3
6 7
3 2
3 1
3 2
2
1 2
3 1

Sample Output

4
3
2
2

题意:t 组数据,每组数据给出 n 个点 m 条边构成一个 DAG 图,然后给出 q 组查询,每组询问从点 x 到点 y 之间有多少个点被删掉后,使得这两个点中的任何一个无法到达另一个

思路:支配树的 DAG 图模版题

首先进行反向拓扑,然后按照拓扑序建立支配树

由于某点的支配树上的父亲就是该点在 DAG 中的所有出点在支配树上的 LCA,因此对于询问 query(x,y),结果也就是 x 的深度与 y 的深度的和减去 LCA(x,y) 的深度

Source Program

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<unordered_map>
#include<bitset>
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define LL long long
#define Pair pair<LL,LL>
LL quickPow(LL a,LL b){ LL res=1; while(b){if(b&1)res*=a; a*=a; b>>=1;} return res; }
LL quickModPow(LL a,LL b,LL mod){ LL res=1; a=a%mod; while(b){if(b&1)res=(a*res)%mod; a=(a*a)%mod; b>>=1;} return res; }
LL getInv(LL a,LL mod){ return quickModPow(a,mod-2,mod); }
LL GCD(LL x,LL y){ return !y?x:GCD(y,x%y); }
LL LCM(LL x,LL y){ return x/GCD(x,y)*y; }
const double EPS = 1E-10;
const int MOD = 998244353;
const int N = 400000+5;
const int dx[] = {-1,1,0,0,1,-1,1,1};
const int dy[] = {0,0,-1,1,-1,1,-1,1};
using namespace std;

int n, m, q;
vector<int> G[N];//原图
vector<int> Gf[N];//反图
int in[N];
int a[N], tot;
int deep[N], dp[N][22];
void topSort() {//对反图进行拓扑排序
    queue<int> Q;
    for (int i = 1; i <= n; i++)
        if (in[i] == 0)
            Q.push(i);

    while (!Q.empty()) {
        a[++tot] = Q.front();
        Q.pop();
        int now = a[tot];
        for (int i = 0; i < Gf[now].size(); i++) {
            int to = Gf[now][i];
            in[to]--;
            if (in[to] == 0)
                Q.push(to);
        }
    }
}
int getLCA(int x, int y) {//获取LCA
    if (deep[x] < deep[y])
        swap(x, y);
    int cnt = deep[x] - deep[y];
    for (int i = 0; i < 20; i++)
        if ((1 << i) & cnt)
            x = dp[x][i];
    if (x == y)
        return x;
    for (int i = 19; i >= 0; i--) {
        if (dp[x][i] != dp[y][i]) {
            x = dp[x][i];
            y = dp[y][i];
        }
    }
    return dp[x][0];
}
void init(){
    tot=0;
    memset(in,0,sizeof(in));
    memset(dp,0,sizeof(dp));
    for (int i = 0; i <= n; i++) {
        G[i].clear();
        Gf[i].clear();
    }
}
int query(int x,int y){
    return deep[x] + deep[y] - deep[getLCA(x, y)];
}
int main() {
    int t;
    scanf("%d",&t);
    while(t--){
        init();
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= m; i++) {
            int x,y;
            scanf("%d%d", &x, &y);
            G[x].push_back(y);
            Gf[y].push_back(x);
            in[x]++;
        }

        topSort();

        for (int i = 1; i <= n; i++) {
            int x = a[i];
            if (G[x].size() == 0) {
                G[0].push_back(x);
                deep[x] = 1;
                continue;
            }
            int y = G[x][0];
            for (int i = 1; i < G[x].size(); i++) 
                y = getLCA(y, G[x][i]);
            deep[x] = deep[y] + 1;
            dp[x][0] = y;
            for (int i = 1; i < 20; i++)
                dp[x][i] = dp[dp[x][i-1]][i-1];
        }

        scanf("%d",&q);
        while(q--) {
            int x,y;
            scanf("%d%d", &x, &y);
            printf("%d\n",query(x,y));
        }
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值