11.5 T1.attack(拓扑+lca)

来源:互联网 发布:linux 批量删除进程 编辑:程序博客网 时间:2024/06/05 18:47

这里写图片描述

分析:
如果整个图是一棵树,那么针对每个询问
必经路径就是k个点的lca到根节点的路径
实际上扩展成一个普通的图也是这样

听男生们在讨论的时候,说这道题和灾难那道题”一样“
我仔细一想,确实哎,
我们现在手上的图是一个DAG
首先我们把ta的拓扑序计算出来
之后构造一个“拓扑树”
假设当前点是x,x的祖先一定都在拓扑树中了

我们要找到与原图中直接指向x的所有点在拓扑树中的lca,把x挂在lca下

(根节点到x的路径一定会经过lca)
处理询问的时候,我们只要在拓扑树上寻找这k个点的lca,输出lca到根节点的结点个数即可

//这里写代码片#include<cstdio>#include<cstring>#include<iostream>#include<cmath>using namespace std;const int INF=0x33333333;const int N=50005;struct node{    int x,y,nxt;};node way[N<<1],e[N<<1];int st[N],tot=0,n,m,q,ste[N],tet=0;int deep[N],pre[N][20],lg,f[N],cnt[N],Q[N],in[N],tou,wei;bool vis[N];void add(int u,int w)                                            //用来top的 {    tet++;    e[tet].x=u;e[tet].y=w;e[tet].nxt=ste[u];ste[u]=tet;}void ad(int u,int w)                                            //用来建树的 {     tot++;    way[tot].x=u;way[tot].y=w;way[tot].nxt=st[u];st[u]=tot;}int LCA(int u,int w){    if (deep[u]<deep[w]) swap(u,w);    int d=deep[u]-deep[w];    if (d)        for (int i=0;i<=lg&&d;i++,d>>=1)            if (d&1)               u=pre[u][i];    if (u==w) return u;    for (int i=lg;i>=0;i--)        if (pre[u][i]!=pre[w][i])        {            u=pre[u][i];            w=pre[w][i];        }    return pre[u][0];}void Top(){    tou=wei=0;    for (int i=1;i<=n;i++) if (in[i]==0) Q[++wei]=i,in[i]=INF;;    while (tou<wei)    {        int now=Q[++tou],lca;        for (int i=ste[now];i;i=e[i].nxt)        {            in[e[i].y]--;            if (in[e[i].y]==0) {                Q[++wei]=e[i].y;                in[e[i].y]=INF;            }        }       }}void doit(){    memset(pre,0,sizeof(pre));    deep[1]=1;    for (int j=2;j<=wei;j++)    {        int now=Q[j];        int lca=-1;        for (int i=st[now];i;i=way[i].nxt)                   //原图中前驱的lca             if (lca==-1) lca=way[i].y;            else lca=LCA(lca,way[i].y);        deep[now]=deep[lca]+1;        pre[now][0]=lca;        for (int i=1;i<=lg;i++)                              //一边添加,一边维护pre             pre[now][i]=pre[pre[now][i-1]][i-1];    }}int main(){    //freopen("attack.in","r",stdin);      //freopen("attack.out","w",stdout);    memset(in,0,sizeof(in));    scanf("%d%d%d",&n,&m,&q);    lg=log(n)/log(2)+1;    for (int i=1;i<=m;i++)    {        int u,w;        scanf("%d%d",&u,&w);        add(u,w); ad(w,u);        in[w]++;    }    Top();    doit();    for (int i=1;i<=q;i++)    {        int x,u,now;        scanf("%d",&x);        scanf("%d",&now);        for (int j=2;j<=x;j++)        {            scanf("%d",&u);            now=LCA(u,now);        }        printf("%d\n",deep[now]);    }    return 0;}