发个模板不算漏题吧.
今天考了一发必经点… 幸好lemonoi给我们考过, 打了个支配树的板子, 但是当时当且只是因为好背所以背下来了, 关于那几个定理实际上并没有证明. 今天考完后复习了一发虽然也没有证明但是重新理解了一下, 在明白半必经点和必经点的定理后, 已经能较准确的写出板子来, 不想考试的时候憋了半天…
话说今天好像要被婊了… 毕竟学的是lemonoil的板子, 基本上没什么差别, 再说他博客里面hdu4694都放了板子. 关键是我和他考试的时候都打的暴力算必经点(没用LCA)… 如有雷同纯属巧合. 苍天在上我考试时没有跟lemonoil有半点交集.
改了新的代码风格后, 重新整理了支配树的板子.
#include<stdio.h>
#include<vector>
#include<cstring>
#define clear(a) memset(a, 0, sizeof(a))
using namespace std;
const int P = 17;
const int maxn = 1e5 + 5;
int n, m, num, q, idx, ans;
int h[maxn], fa[maxn];
int dfn[maxn], id[maxn];
int bcjf[maxn], best[maxn];
int semi[maxn], idom[maxn];
int dep[maxn], anc[maxn][P + 1];
vector<int> pre[maxn], dom[maxn];
struct edge
{
int nxt, v;
}e[maxn * 2];
inline void add(int u ,int v, int opt)
{
e[++num].v = v, e[num].nxt= h[u], h[u] = num;
if(opt) pre[v].push_back(u);
}
inline int pushd(int u)
{
if(u == bcjf[u]) return u;
int ff = pushd(bcjf[u]);
if(dfn[semi[best[bcjf[u]]]] < dfn[semi[best[u]]]) best[u] = best[bcjf[u]];
return bcjf[u] = ff;
}
inline void dfs(int u)
{
dfn[u] = ++ idx;
id[idx] = u;
for (int i = h[u]; i; i = e[i].nxt)
if(!dfn[e[i].v])
dfs(e[i].v), fa[e[i].v] = u;
}
inline void Lengauer_Tarjan()
{
dfs(1);
for (int i = 1; i <= n; ++ i) semi[i] = best[i] = bcjf[i] = i;
for (int i = idx; i >= 2; -- i)
{
int u = id[i];
for (int p = 0; p < pre[u].size(); ++ p)
{
int v = pre[u][p];
if(!dfn[v]) continue;
pushd(v);
if(dfn[semi[best[v]]] < dfn[semi[u]]) semi[u] = semi[best[v]];
}
dom[semi[u]].push_back(u);
bcjf[u] = fa[u];
u = id[i - 1];
for (int p = 0; p < dom[u].size(); ++ p)
{
int v = dom[u][p];
pushd(v);
if(semi[best[v]] == u) idom[v] = u;
else idom[v] = best[v];
}
}
for (int i = 2; i <= idx; ++i)
{
int u = id[i];
if(idom[u] != semi[u]) idom[u] = idom[idom[u]];
}
}
inline int query(int u, int v)
{
if(dep[u] < dep[v]) swap(u, v);
int t = dep[u] - dep[v];
for (int i = 0; i <= P; ++ i)
if(t & (1 << i)) u = anc[u][i];
for (int i = P; i >= 0; --i)
if(anc[u][i] != anc[v][i])
u = anc[u][i], v = anc[v][i];
return (u == v) ? u : anc[u][0];
}
inline void dfs_tree(int u)
{
for (int i = 1; i <= P; ++ i)
{
if(dep[u] < (1 << i)) break;
anc[u][i] = anc[anc[u][i - 1]][i - 1];
}
for (int i = h[u]; i; i = e[i].nxt)
{
anc[e[i].v][0] = u;
dep[e[i].v] = dep[u] + 1;
dfs_tree(e[i].v);
}
}
int main()
{
scanf("%d%d%d", &n, &m, &q);
int u, v;
for (int i = 1; i <= m; ++ i)
{
scanf("%d%d", &u, &v);
add(u, v, 1);
}
Lengauer_Tarjan();
num = 0, clear(h);
for (int i = 2; i <= n; ++ i)
add(idom[i], i, 0);
dep[1] = 1, anc[1][0] = 1;
dfs_tree(1);
for (int i = 1; i <= q; ++ i)
{
int k;
ans = 0;
scanf("%d%d", &k, &u);
for (int j = 1; j < k; ++ j)
scanf("%d", &v), u = query(u, v);
printf("%d\n", dep[u]);
}
}