题目描述
给出一个无向图(n<=50000,m<=100000),q个询问(q<=100000),每次询问节点1到k个点的必经点的个数(k<=100000).
输入数据:
4 3 2
1 2
2 3
2 4
2 3 4
2 2 4
输出数据:
2
2
【解题报告】
思路应该比较好想,构建出支配树后求着k个点的LCA,LCA的深度即为答案。
然而我在考场上并不会支配树。。。
代码如下:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
#define N 50010
#define M 100010
int n,m,q;
int cnt=-1,head[N],pre[N],dom[N],ss[N];
struct Edge{int to,nxt;}e[M<<2];
int bcj[N],semi[N],idom[N],best[N],dfn[N],id[N],fa[N],idc;
void adde(int *head,int u,int v)
{
e[++cnt].to=v;
e[cnt].nxt=head[u];
head[u]=cnt;
}
void init()
{
memset(head,-1,sizeof(head));
memset(pre,-1,sizeof(pre));
memset(dom,-1,sizeof(dom));
memset(ss,-1,sizeof(ss));
scanf("%d%d%d",&n,&m,&q);
for(int i=1,u,v;i<=m;++i)
{
scanf("%d%d",&u,&v);
adde(head,u,v);
adde(pre,v,u);
}
}
namespace Dominator_Tree
{
int find(int v)//\xb4\xf8Ȩ\xb2\xa2\xb2鼯·\xbe\xb6ѹ\xcb\xf5
{
if(v==bcj[v]) return v;
int y=find(bcj[v]);
if(dfn[semi[best[bcj[v]]]]<dfn[semi[best[v]]]) best[v]=best[bcj[v]];
return bcj[v] = y;
}
void dfs(int rt)//\xc7\xf3\xb3\xf6dfs\xd0\xf2
{
dfn[rt]=++idc;
id[idc]=rt;
for(int i=head[rt];~i;i=e[i].nxt)
{
if(!dfn[e[i].to])
{
dfs(e[i].to);
fa[e[i].to]=rt;
}
}
}
void tarjan()
{
for(int i=idc,u;i>=2;--i)
{
u=id[i];
for(int j=pre[u];~j;j=e[j].nxt)//semi
{
int v=e[j].to;
if(!dfn[v]) continue;
find(v);
if(dfn[semi[best[v]]]<dfn[semi[u]]) semi[u]=semi[best[v]];
}
adde(dom,semi[u],u);
bcj[u]=fa[u];u=id[i-1];
for(int j=dom[u];~j;j=e[j].nxt)
{
int v=e[j].to;
find(v);
if(semi[best[v]]==u) idom[v]=semi[v];
else idom[v]=best[v];
}
}
for(int i=2,u;i<=idc;++i)
{
u=id[i];
if(idom[u]!=semi[u]) idom[u]=idom[idom[u]];
}
}
}
namespace LCA
{
int dep[N],ff[N][18];
void get_st(int u)
{
for(int i=ss[u];~i;i=e[i].nxt)
{
int v=e[i].to;
if(v==ff[u][0]) continue;
ff[v][0]=u;
dep[v]=dep[u]+1;
get_st(v);
}
}
int query(int u,int v)
{
if(dep[u]<dep[v]) swap(u,v);
int len=dep[u]-dep[v];
for(int p=0;len;p++,len>>=1)
if(len&1) u=ff[u][p];
if(u==v) return u;
for(int j=17;j>=0;--j)
{
if(ff[u][j]==ff[v][j]) continue;
u=ff[u][j];
v=ff[v][j];
}
return ff[u][0];
}
}
using namespace Dominator_Tree;
using namespace LCA;
void solve()
{
for(int i=1;i<=n;++i) bcj[i]=semi[i]=best[i]=i;
dfs(1);
tarjan();
for(int i=2;i<=n;++i) adde(ss,idom[i],i);
dep[1]=1;ff[1][0]=1;
get_st(1);
for(int j=1;j<18;++j)
for(int i=1;i<=n;++i)
ff[i][j]=ff[ff[i][j-1]][j-1];
while(q--)
{
int k,u,v;
scanf("%d",&k);
scanf("%d",&u);
for(int i=2;i<=k;++i)
{
scanf("%d",&v);
u=query(u,v);
}
printf("%d\n",dep[u]);
}
}
int main()
{
freopen("attack.in","r",stdin);
freopen("attack.out","w",stdout);
init();
solve();
return 0;
}