2737: 狼与羊的故事
Result | TIME Limit | MEMORY Limit | Run Times | AC Times | JUDGE |
---|---|---|---|---|---|
3s | 65536K | 53 | 10 | Standard |
村长要召开羊族大会,讨论羊族未来的发展,要求羊羊们到指定地点集合。小羊们收到通知后从家里出发到达指定地点。每个羊的家都是与其他羊的家连通的,可以互相访问。 比如说可以从1到3,同样也可以从3到1 。灰太郎听到这个消息后,准备有所行动(你懂的)。但他不知道应该在哪条路上等羊。 但他知道,有的路线一定要进过某条边。如上图从1到5一定要经过4-5这条路,这样他可以在那条路上事先埋伏好。现在他想知道2个点之间有多少这样的路。如果没有输出0.
Input
第一行有两个整数N,M。表示有N(1<N<10001)个家,M(1<M<10001)条路线。随后有M行,每行有两个不相同的整数A、B表示 A,B之间有一条路。我们保证任意时刻任意两个地点都能够相互到达并且2点之间最多只有1条路。接下来输入一个数K(K<20001)表示有K次查询。随后有K行。 每行有两个不相同的整数A、B询问 A,B之间有多少条的那样的路。
Output
对于每个询问输出有多少条那样的路。
Sample Input
5 5 1 2 3 4 2 4 3 1 5 4 4 1 5 3 5 2 3 4 1
Sample Output
1 1 0 0
Problem Source: 毛有祥
大概思路:求桥边,之后去掉缩点,之后求LCA。
代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <time.h>
using namespace std;
const int MAXN = 10001;
const int MAXK = 20010;
const int MAXQ = 20010;
struct Edge
{
int end;
int next;
} st[MAXK * 2], ans[MAXK * 2], ss[MAXK * 2];
int head[MAXN], father[MAXN], dfn[MAXN], low[MAXN], root[MAXN];
int parent[MAXN], headq[MAXN], dis[MAXN], p[MAXN], Head[MAXN];
bool flag[MAXN];
int cnt, n, m, iindex, top, scnt, nnum;
struct Que
{
int next, b, num;
} query[MAXQ * 2];
int qq[MAXQ];
inline int min(int a, int b)
{
return a > b ? b : a;
}
void init()
{
memset(head, -1, sizeof(int) * (n + 1));
memset(father, -1, sizeof(int) * (n + 1));
memset(dfn, -1, sizeof(int) * (n + 1));
memset(low, -1, sizeof(int) * (n + 1));
memset(root, -1, sizeof(int) * (n + 1));
memset(parent, -1, sizeof(int) * (n + 1));
memset(headq, -1, sizeof(int) * (n + 1));
memset(dis, -1, sizeof(int) * (n + 1));
memset(flag, false, sizeof(bool) * (n + 1));
memset(p, -1, sizeof(int) * (n + 1));
memset(Head, -1, sizeof(int) * (n + 1));
for (int i = 0; i < n; ++i)
{
parent[i] = i;
root[i] = 1;
}
nnum = scnt = cnt = iindex = top = 0;
}
int find(int a)
{
int e = a, j;
while (root[e] == 0) e = parent[e];
while (a != e)
{
j = parent[a];
parent[a] = e;
a = j;
}
return e;
}
void uf(int a, int b)
{
a = find(a);
b = find(b);
if (a == b) return;
if (root[a] >= root[b])
{
parent[b] = a;
root[a] += root[b];
root[b] = 0;
}
else
{
parent[a] = b;
root[b] += root[a];
root[a] = 0;
}
}
void add(int a, int b)
{
st[cnt].next = head[a];
st[cnt].end = b;
head[a] = cnt;
cnt++;
}
void dfs(int u)
{
Edge e;
int v;
low[u] = dfn[u] = iindex++;
for (int i = head[u]; i != -1; i = st[i].next)
{
v = st[i].end;
if (dfn[v] == -1)
{
father[v] = u;
dfs(v);
low[u] = min(low[u], low[v]);
if (low[v] == dfn[v])
{
e.end = u;
e.next = v;
ans[top++] = e;
}
else
{
uf(u, v);
}
}
else
if (v != father[u])
{
low[u] = min(low[u], dfn[v]);
}
}
return;
}
void add2(int a, int b)
{
ss[nnum].next = Head[a];
ss[nnum].end = b;
Head[a] = nnum;
nnum++;
}
void add3(int a, int b, int c)
{
query[scnt].next = headq[a];
query[scnt].b = b;
query[scnt].num = c;
headq[a] = scnt;
scnt++;
}
int find1(int u)
{
if (p[u] == -1) return u;
else
{
p[u] = find1(p[u]);
return p[u];
}
}
void tarjan(int u, int dep)
{
int a, b;
dis[u] = dep;
flag[u] = true;
for (int i = Head[u]; i != -1; i = ss[i].next)
{
a = ss[i].end;
if (!flag[a])
{
tarjan(a, dep + 1);
p[a] = u;
}
}
for (int i = headq[u]; i != -1; i = query[i].next)
{
a = query[i].b;
b = query[i].num;
if (flag[a])
{
qq[b] = dis[a] + dis[u] - 2 * dis[find1(a)];
}
}
}
int main()
{
int a, b, q;
while (scanf("%d%d", &n, &m) != EOF)
{
init();
for (int i = 0; i < m; ++i)
{
scanf("%d%d", &a, &b);
add(a, b);
add(b, a);
}
dfs(0);
scanf("%d", &q);
for (int i = 0; i < q; ++i)
{
scanf("%d%d", &a, &b);
a = find(a);
b = find(b);
if (a == b) qq[i] = 0;
else
{
add3(a, b, i);
add3(b, a, i);
}
}
for (int i = 0; i < top; ++i)
{
a = ans[i].end;
b = ans[i].next;
a = find(a);
b = find(b);
add2(a, b);
add2(b, a);
}
tarjan(a, 0);
for (int i = 0; i < q; ++i)
{
printf("%d\n", qq[i]);
}
}
return 0;
}