Tarjan 总结

Tarjan 总结


写在前面的话

终于弄完了…QAQ


Tarjan求强连通分量

DFN[u] 为访问u节点的时间截, LOW[u] 为u节点能通过边访问到的最小的DFN[]的值,对于在同一个强连通分量的点,其根节点的 LOW[] 为这些点中最小的,并且满足 LOW[u]==DFN[u] ,那么可以使用栈来记录在访问 u 节点后,访问的节点,并且这些节点在同一个强连通分量中,再将它们标记,出栈即可;

void Tarjan(int u)
{
    vis[stack[++index]=u]=1,DFN[u]=LOW[u]=++dfs_num;
    for(int i=head[u];i;i=edge[i].next)
        if(!DFN[edge[i].to])
            Tarjan(edge[i].to),
            LOW[u]=min(LOW[u],LOW[edge[i].to]);
        else if(vis[edge[i].to])    LOW[u]=min(LOW[u],DFN[edge[i].to]);
    if(LOW[u]==DFN[u])
    {
        vis[u]=0,dye[u]=++CNT;
        while(u!=stack[index])
        {
            vis[stack[index]]=0;
            dye[stack[index--]]=CNT;
        }
        index--;
    }
}

Network of Schools

POJ-1236
题目大意:
各节点之间存在单向边,某个节点得到软件后可以向相连的节点传输,
Q1:求最少发送多少软件,可以使全部节点得到软件,
Q2:求至少需要添加多少条边,使任意点之间能够联通

TJ
首先强联通分量乱搞,对于Q1,只需要找缩完点后入度为0的联通块的个数,对于Q2,要使所有的联通块均有出入度,只需要加上max(0num0num),注意特判当图中只有一个联通块的时候,不需要加边

King’s Quest

POJ-1904
题目大意
国王有 n 个王子,现在有n个王子和 n 个女孩的配对名单,同时可能有某些王子喜欢多个女孩,求每个王子可以和哪些女孩结婚(保证其他王子能够选择自己心仪女生);

TJ
对于每个王子的心仪女孩,都连一条从王子到女孩的红线有向边,再从巫师的名单中添加从钦定女孩至王子的有向边,跑强连通分量,最后对于某王子,在同一强连通分量里的女孩都是可以选的

Directed Roads

Codeforces-711D

题目大意
给定一个图,n个点 n 条边,每条边可以反向,问有多少种方法使得图中没有环

TJ
对于在同一个强连通分量中的点,将边反向的方案数为2size[scc],同时要满足没有环,还要减去 2 (一条边都没有反向和所有边都反向的情况),如果该强连通分量中只有一个点,那么在最后,统计这些点的个数,ans=ans2k,因为这些点无论是否反向,在这些区域都不会出现环

Checkposts

Codeforces-427C

题目大意
给定一个有向图,每个节点有一个权值,在每个强连通分量中选一个点,求最小权值和在权值和最小的情况下可以选择的方案数

TJ
Tarjan乱搞,弄完之后在每个强联通分量中局部枚举,方案数乘法原理乘一下就好了

HAOI2010软件安装

Codevs-1866

题目大意
对于每个软件都有一个占用空间 wi ,还要一个价值 vi ,同时某些软件之间存在依赖关系,求在给定的 wmax 下得到的最大的 vmax

TJ
建立从被依赖的软件到需要依赖的软件的一条有向边,跑一遍Tarjan缩点,然后跑树上的背包DP,(泛化背包)




Tarjan求割点

割点,即删去该点和所有与该点相连的边后,图变成不连通的多个联通块
对于某个点 u ,如果该点成为割点,需满足在该点所连的某点v中存在 LOW[v]>=DFN[u] ,那么该点 u 即为割点,(因为对于点v无法到达比 u 更上面的点,最多也就到达点u),或者对于根节点u,存在多个儿子,即 son>1

void tarjan(int u,int fa)
{
    DFN[u]=LOW[u]=++dfs_num,vis[u]=1;
    for(int i=head[u];i;i=E[i].next)
    {
        int to=E[i].to;
        if(to==fa)  continue;
        if(!DFN[to])
        {
            tarjan(to,u);
            LOW[u]=min(LOW[u],LOW[to]);
            if(u==ant)  son++; //情况2的特判
            if(LOW[to]>=DFN[u] && u!=ant)   cnt[u]=1;   
        }
        else if(vis[to])    LOW[u]=min(LOW[u],DFN[to]);
    }
}

新年的毒瘤

UOJ-67

题目大意
给定一个有 n 个节点的m条无向边的图,现在要求出图中所有的毒瘤点
毒瘤点的定义:删去该点 u 之后,图成为树

TJ
考虑这样的节点u,一定不是割点(因为要成为树),同时删去该点之后图中有 n1 个点,同时有 n2 条边,那么删去的该点的度需满足 deg=mn+2 ,跑一遍即可

HNOI2012 矿场搭建

BZOJ-2730

题目大意
给定一个无向图,求某个点爆炸后,其他点的工人仍有一条到达出口的道路,求需设置的最少出口和方案数

TJ
考虑割点,如果多个割点同时存在一个联通块中,那么就不必设置出口,因为某个割点爆炸后,还可以从其他割点出去,如果一个联通块中只有一个割点,那么就必须设置一个出口,并且不能设置在割点上,如果该联通块中没有割点,那么就要设置两个,防止其中一个爆炸

POI2008 BLO-Blockade

Luogu-3469

题目大意
很清楚…注意该点也包含在答案内

TJ
对于割点,封锁后分成的联通块之间的点不能相互到达,记忆化搜索,统计答案




Tarjan求割边(桥)

只需要将判断条件改为 LOW[v]>DFN[u] ,即可,因为对于某点如果无法到达父亲节点以上的节点,那么该点的边为桥


网络的关键边

Vijos-1769

题目大意
在给定的无向图中,某些点提供A或B服务,现要求求出所有的关键边
关键边的定义为:删去某条边 E 后,存在某个节点无法接受A或B服务

TJ
分析得到,关键边一定存在于桥上,并且要满足经过传递之后该边所连的点中的A,或B的值为0或k,l,那么删去该边之后一定存在某些点无法获得 A,B 服务

POJ-1236 Network of Schools
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int MAXN=100+10;

int LOW[MAXN],DFN[MAXN],n,m,t,dfs_num,ans2;

int dye[MAXN],CNT,stack[MAXN],index1,size[MAXN];

int head[MAXN],num,ans1,in[MAXN],out[MAXN];

bool vis[MAXN];

struct Edge{
    int from,to,next;
}edge[MAXN<<5];

void Add(int from,int to)
{
    edge[++num].from=from;
    edge[num].to=to;
    edge[num].next=head[from];
    head[from]=num;
}

void Tarjan(int u)
{
    vis[stack[++index1]=u]=1;
    DFN[u]=LOW[u]=++dfs_num;
    for(int i=head[u];i;i=edge[i].next)
        if(!DFN[edge[i].to])
        {
            Tarjan(edge[i].to);
            LOW[u]=min(LOW[u],LOW[edge[i].to]);
        }
        else if(vis[edge[i].to]) LOW[u]=min(LOW[u],DFN[edge[i].to]);
    if(DFN[u]==LOW[u])
    {
        vis[u]=0;
        size[dye[u]=++CNT]++;
        while(u!=stack[index1])
        {
            dye[stack[index1]]=CNT;
            vis[stack[index1--]]=0;
            size[CNT]++;
        }
        index1--;
    }

}

void init()
{
    memset(size,0,sizeof size);
    memset(vis,0,sizeof vis);
    memset(DFN,0,sizeof DFN);
    memset(dye,0,sizeof dye);
    memset(LOW,0,sizeof LOW);
    num=0,CNT=0,index1=0,dfs_num=0,ans1=0,ans2=0;
    memset(edge,0,sizeof edge);
    memset(head,0,sizeof head);
    memset(in,0,sizeof in);
    memset(out,0,sizeof out);
}

int main()
{
    while(scanf("%d",&n)!=EOF)
    {   
        init();
        for(int i=1;i<=n;i++)
        {
            while(scanf("%d",&t))
            {
                if(t==0)    break;
                Add(i,t);
            }
        }
        for(int i=1;i<=n;i++)
            if(!dye[i]) Tarjan(i);
        for(int i=1;i<=num;i++)
        {
            if(dye[edge[i].from]!=dye[edge[i].to])
            {
                in[dye[edge[i].to]]++;
                out[dye[edge[i].from]]++;
            }
        }


        for(int i=1;i<=CNT;i++)
        {
            if(in[i]==0)    ans1++;
            if(out[i]==0)   ans2++;
        }

        if(CNT==1)  printf("1\n0\n");   

        else printf("%d\n%d\n",ans1,max(ans1,ans2));
    }
    return 0;
}
POJ-1904 King’s Quest
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>

using namespace std;

const int MAXN=10000+10;

int LOW[MAXN],DFN[MAXN],dfs_num,dye[MAXN],in[MAXN],CNT,n1,tmp[MAXN];

int stack[MAXN],index1,n,m,x,y,head[MAXN],num,size[MAXN],k,a[MAXN],cnt[MAXN];

bool vis[MAXN];

struct Edge{
    int from,to,next;
}E[MAXN<<5];

void Add(int from,int to)
{
    E[++num].from=from;
    E[num].to=to;
    E[num].next=head[from];
    head[from]=num;
}

void tarjan(int u)
{
    vis[stack[++index1]=u]=1;
    DFN[u]=LOW[u]=++dfs_num;
    for(int i=head[u];i;i=E[i].next)
        if(!DFN[E[i].to])
            tarjan(E[i].to),LOW[u]=min(LOW[u],LOW[E[i].to]);
        else if(vis[E[i].to])   LOW[u]=min(LOW[u],DFN[E[i].to]);
    if(DFN[u]==LOW[u])
    {
        dye[u]=++CNT,vis[u]=0,size[CNT]++;
        while(u!=stack[index1])
        {
            dye[stack[index1]]=CNT;
            size[CNT]++;
            vis[stack[index1--]]=0;
        }
        index1--;
    }
}


void init()
{
    memset(size,0,sizeof size);
    memset(vis,0,sizeof vis);
    memset(DFN,0,sizeof DFN);
    memset(dye,0,sizeof dye);
    memset(LOW,0,sizeof LOW);
    num=CNT=index1=dfs_num=0;
    memset(E,0,sizeof E);
    memset(head,0,sizeof head);
}

bool cmp(int A,int B)   {return A<B;}

int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        init();
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&n1);
            for(int j=1;j<=n1;j++)
            {
                scanf("%d",&x);
                Add(i+n,x);
            }
        }
        for(int i=1;i<=n;i++)   {scanf("%d",&x);Add(x,i+n);}
        for(int i=1;i<=n+n;i++)
            if(!dye[i]) tarjan(i);
        for(int i=n+1;i<=n+n;i++)
        {
            memset(tmp,0,sizeof tmp);
            for(int j=head[i];j;j=E[j].next)
                if(dye[E[j].to]==dye[i])    tmp[++tmp[0]]=E[j].to;
            sort(tmp+1,tmp+tmp[0]+1,cmp);
            printf("%d ",tmp[0]);
            for(int j=1;j<=tmp[0];j++)  printf("%d ",tmp[j]);
            puts("");
        }
    }
    return 0;
}
Codeforces-711D Directed Roads
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;

const int MAXN=200000+10;

const int INF=0x7fffffff;

const int MOD=1000000007;

int LOW[MAXN],DFN[MAXN],dfs_num,dye[MAXN],in[MAXN],CNT,minn[MAXN];

int stack[MAXN],index1,n,m,x,y,head[MAXN],num,size[MAXN],k;

LL ans=1;

bool vis[MAXN];

struct Edge{
    int from,to,next;
}E[MAXN<<2];

void Add(int from,int to)
{
    E[++num].from=from;
    E[num].to=to;
    E[num].next=head[from];
    head[from]=num;
}

void tarjan(int u)
{
    vis[stack[++index1]=u]=1;
    DFN[u]=LOW[u]=++dfs_num;
    for(int i=head[u];i;i=E[i].next)
        if(!DFN[E[i].to])
            tarjan(E[i].to),LOW[u]=min(LOW[u],LOW[E[i].to]);
        else if(vis[E[i].to])   LOW[u]=min(LOW[u],DFN[E[i].to]);
    if(DFN[u]==LOW[u])
    {
        dye[u]=++CNT,vis[u]=0,size[CNT]++;
        while(u!=stack[index1])
        {
            dye[stack[index1]]=CNT;
            size[CNT]++;
            vis[stack[index1--]]=0;
        }
        index1--;
    }
}

void init()
{
    memset(vis,0,sizeof vis);
    memset(dye,0,sizeof dye);
    memset(E,0,sizeof E);
    memset(LOW,0,sizeof LOW);
    memset(stack,0,sizeof stack);
    memset(DFN,0,sizeof DFN);
    memset(in,0,sizeof in);
    memset(head,0,sizeof head);
    for(int i=1;i<=MAXN;i++)    minn[i]=INF;
    num=dfs_num=ans=index1=CNT=0;
}

LL pow(LL a,LL b)
{
    LL ans1=1,p=a;
    while(b)
    {
        if(b & 1)   ans1=(ans1*p)%MOD;
        p=(p*p)%MOD;
        b>>=1;
    }
    return ans1%MOD;
}


int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        init();
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&x);
            Add(i,x);
        }
        for(int i=1;i<=n;i++)
            if(!dye[i]) tarjan(i);
        ans=1;
        for(int i=1;i<=CNT;i++)
            if(size[i]>1) ans=(ans*(pow(2,size[i])%MOD-2))%MOD;
            else if(size[i]==1) k++;
        if(k!=0)    ans=ans*pow(2,k)%MOD;
        printf("%lld\n",ans);
    }
}
Codeforces-427C Checkposts
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;

const int MAXN=200000+10;

const int INF=0x7fffffff;

const int MOD=1000000007;

int LOW[MAXN],DFN[MAXN],dfs_num,dye[MAXN],in[MAXN],CNT,minn[MAXN];

int stack[MAXN],index1,n,m,x,y,head[MAXN],num,size[MAXN],k,a[MAXN],cnt[MAXN];

LL ans=1;

bool vis[MAXN];

struct Edge{
    int from,to,next;
}E[MAXN<<2];

void Add(int from,int to)
{
    E[++num].from=from;
    E[num].to=to;
    E[num].next=head[from];
    head[from]=num;
}

void tarjan(int u)
{
    vis[stack[++index1]=u]=1;
    DFN[u]=LOW[u]=++dfs_num;
    for(int i=head[u];i;i=E[i].next)
        if(!DFN[E[i].to])
            tarjan(E[i].to),LOW[u]=min(LOW[u],LOW[E[i].to]);
        else if(vis[E[i].to])   LOW[u]=min(LOW[u],DFN[E[i].to]);
    if(DFN[u]==LOW[u])
    {
        dye[u]=++CNT,vis[u]=0,size[CNT]++;
        while(u!=stack[index1])
        {
            dye[stack[index1]]=CNT;
            size[CNT]++;
            vis[stack[index1--]]=0;
        }
        index1--;
    }
}

LL pow(LL a,LL b)
{
    LL ans1=1,p=a;
    while(b)
    {
        if(b & 1)   ans1=(ans1*p)%MOD;
        p=(p*p)%MOD;
        b>>=1;
    }
    return ans1%MOD;
}


int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        Add(x,y);
    }
    for(int i=1;i<=n;i++)
        if(!dye[i]) tarjan(i);
    LL ans=1,anss=0;
    for(int i=1;i<=CNT;i++) minn[i]=INF;
    for(int i=1;i<=n;i++)
        if(minn[dye[i]]==a[i])  cnt[dye[i]]++;
        else if(minn[dye[i]]>a[i])  minn[dye[i]]=a[i],cnt[dye[i]]=1;
    for(int i=1;i<=CNT;i++)
        anss+=minn[i],ans=(ans*cnt[i])%MOD;
    printf("%lld %lld\n",anss,ans%MOD);
    return 0;
}
Codevs-1866 HAOI2010软件安装
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>

using namespace std;

const int MAXN=500+10;

int DFN[MAXN],LOW[MAXN],n,m,dfs_num,num,dye[MAXN],x,ans,num2,head1[MAXN],in[MAXN];

int stack[MAXN],index1,CNT,head[MAXN],w[MAXN],val[MAXN],f[MAXN][MAXN];

bool vis[MAXN];

struct Edge{
    int from,to,next;
}E[MAXN<<1],E1[MAXN<<1];

struct Point{
    int v,w,d;
}p[MAXN];

void Add(int from,int to)
{
    E[++num].to=to;
    E[num].from=from;
    E[num].next=head[from];
    head[from]=num;
}

void Add2(int from,int to)
{
    in[to]++;
    E1[++num2].to=to;
    E1[num2].from=from;
    E1[num2].next=head1[from];
    head1[from]=num2;
}

void tarjan(int u)
{
    vis[stack[++index1]=u]=1,DFN[u]=LOW[u]=++dfs_num;
    for(int i=head[u];i;i=E[i].next)
        if(!DFN[E[i].to])   
            tarjan(E[i].to),LOW[u]=min(LOW[u],LOW[E[i].to]);
        else if(vis[E[i].to])   LOW[u]=min(LOW[u],DFN[E[i].to]);
    if(LOW[u]==DFN[u])
    {
        vis[u]=0,p[++CNT].w=w[u],p[CNT].v=val[u],dye[u]=CNT;
        while(u!=stack[index1])
        {
            vis[stack[index1]]=0,p[CNT].w+=w[stack[index1]];
            p[CNT].v+=val[stack[index1]],dye[stack[index1--]]=CNT;
        }
        index1--;
    }
}

void dfs(int pos)
{
    for(int i=head1[pos];i;i=E1[i].next)
    {
        dfs(E1[i].to);
        for(int j=m-p[pos].w;j>=0;j--)
            for(int k=0;k<=j;k++)
                f[pos][j]=max(f[pos][j],f[pos][k]+f[E1[i].to][j-k]);
    }
    for(int j=m;j>=0;j--)
        if(j>=p[pos].w) f[pos][j]=f[pos][j-p[pos].w]+p[pos].v;
        else f[pos][j]=0;
}

bool cmp(Point A,Point B)   {return A.w<B.w;}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&w[i]);
    for(int i=1;i<=n;i++)
        scanf("%d",&val[i]);
    for(int i=1;i<=n;i++)
        {scanf("%d",&x);if(x!=0) Add(x,i);}
    for(int i=1;i<=n;i++)
        if(!DFN[i]) tarjan(i);
    for(int i=1;i<=num;i++)
        if(dye[E[i].to]!=dye[E[i].from])  Add2(dye[E[i].from],dye[E[i].to]);
    for(int i=1;i<=CNT;i++)
        if(in[i]==0)    Add2(CNT+1,i);
        dfs(CNT+1);
    printf("%d\n",f[CNT+1][m]);
    return 0;
}
UOJ-67 新年的毒瘤
#include <cstdio>
#include <algorithm>

using namespace std;

const int MAXN=500000+10;

int DFN[MAXN],LOW[MAXN],dfs_num,num,tmp[MAXN],n,m,x,y,in[MAXN];

int head[MAXN],son,ans[MAXN],ant;

bool vis[MAXN],cnt[MAXN];

struct Edge{
    int from,to,next;
}E[MAXN<<1];

void Add(int from,int to)
{
    E[++num].from=from;
    E[num].to=to;
    E[num].next=head[from];
    head[from]=num;
}

void tarjan(int u,int fa)
{
    DFN[u]=LOW[u]=++dfs_num,vis[u]=1;
    for(int i=head[u];i;i=E[i].next)
    {
        int to=E[i].to;
        if(to==fa)  continue;
        if(!DFN[to])
        {
            tarjan(to,u);
            LOW[u]=min(LOW[u],LOW[to]);
            if(u==ant)  son++;
            if(LOW[to]>=DFN[u] && u!=ant)   cnt[u]=1;   
        }
        else if(vis[to])    LOW[u]=min(LOW[u],DFN[to]);
    }
}

bool cmp(int A,int B)   {return A<B;}

int main()
{

    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        Add(x,y),Add(y,x);
    }
    for(int i=1;i<=n;i++)
        if(!DFN[i])
        {
            son=0,ant=i;
            tarjan(i,-1);
            if(son>1)   cnt[ant]=1;
        }
    for(int i=1;i<=num;i++)
        in[E[i].to]++;
    for(int i=1;i<=n;i++)
        if(!cnt[i] && in[i]==m-n+2 )
        ans[++ans[0]]=i;
    sort(ans+1,ans+ans[0]+1,cmp);
    printf("%d\n",ans[0]);
    for(int i=1;i<=ans[0];i++)
        printf("%d ",ans[i]);
    return 0;
}
HNOI2012 矿场搭建
#include <cstdio>
#include <algorithm>
#include <cstring>

using namespace std;

typedef long long LL;

const int MAXN=4000+10;

int LOW[MAXN],DFN[MAXN],num,dfs_num,CNT,head[MAXN],n,x,y,ant,k,son,maxn,case1;

LL ans1,ans2;

bool vis[MAXN],cnt[MAXN];

struct Edge{
    int from,to,next;
}E[MAXN<<1];

void Add(int from,int to)
{
    E[++num].from=from;
    E[num].to=to;
    E[num].next=head[from];
    head[from]=num;
}

void tarjan(int u,int fa)
{
    LOW[u]=DFN[u]=++dfs_num,vis[u]=1;
    for(int i=head[u];i;i=E[i].next)
    {
        int to=E[i].to;
        if(to==fa)  continue;
        if(!DFN[to])
        {
            tarjan(to,u);
            LOW[u]=min(LOW[u],LOW[to]);
            if(u==ant)  son++;
            if(LOW[to]>=DFN[u] && u!=ant)
                cnt[u]=1;
        }   
        else if(vis[to]) LOW[u]=min(LOW[u],DFN[to]);
    }
}

void dfs(int u)
{
    DFN[u]=k;
    if(cnt[u])  return ;
    x++;
    for(int i=head[u];i;i=E[i].next)
    {
        int to=E[i].to;
        if(cnt[to] && DFN[to]!=k)   CNT++,DFN[to]=k;
        if(!DFN[to]) dfs(to);
    }
}

void init()
{
    memset(vis,0,sizeof vis);
    memset(DFN,0,sizeof DFN);
    memset(head,0,sizeof head);
    memset(E,0,sizeof E);
    memset(LOW,0,sizeof LOW);
    memset(cnt,0,sizeof cnt);
    num=CNT=ans1=dfs_num=maxn=k=0;
    ans2=1;
}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        if(n==0)    break;
        init();
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&x,&y);
            Add(x,y),Add(y,x);
            maxn=max( maxn, max(x,y) );
        }
        for(int i=1;i<=maxn;i++)
        {   
            if(!DFN[i]) 
            {   
                son=0;ant=i;
                tarjan(i,-1);
                if(son>=2)  cnt[ant]=1;
            }
        }
        memset(DFN,0,sizeof DFN);
        for(int i=1;i<=maxn;i++)
        {
            if( !DFN[i] && !cnt[i] )
            {
                CNT=x=0,k++;
                dfs(i);
                if(!CNT)    ans1+=2,ans2*=( x * (x-1) ) /2;
                if(CNT==1)  ans1++,ans2*=x;
            }
        }
        printf("Case %d: %lld %lld\n",++case1,ans1,ans2);
    }
    return 0;
}
POI2008 BLO-Blockade
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int MAXN=100000+10;

typedef long long LL;

int DFN[MAXN],LOW[MAXN],n,m,dfs_num,CNT,a,b;

int sum[MAXN],head[MAXN],num;
LL size[MAXN],ans[MAXN];

struct Edge{
    int from,to,next;
}E[MAXN<<4];

void Add(int from,int to)
{
    E[++num].from=from;
    E[num].to=to;
    E[num].next=head[from];
    head[from]=num;
}

void tarjan(int u,int fa)
{
    LL t=0;
    DFN[u]=LOW[u]=++dfs_num;
    size[u]=1;
    for(int i=head[u];i;i=E[i].next)
    {
        if(E[i].to==fa)    continue;
        if(!DFN[E[i].to])
        {
            tarjan(E[i].to,u);
            size[u]+=size[E[i].to];
            LOW[u]=min(LOW[u],LOW[E[i].to]);
            if(LOW[E[i].to]>=DFN[u])
            {
                ans[u]+=t*size[E[i].to];
                t+=size[E[i].to];
            }
        }
        else if(size[E[i].to])    LOW[u]=min(LOW[u],DFN[E[i].to]);    
    }
    ans[u]+=t*(n-t-1);
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&a,&b);
        Add(a,b),Add(b,a);
    }
    tarjan(1,-1);
    for(int i=1;i<=n;i++)
        printf("%lld\n",ans[i]+(n-1)<<1);
    return 0;
}
Vijos-1769 网络的关键边
#include <cstdio>
#include <algorithm>
#include <cstring>

using namespace std;

const int MAXN=200000+10;

int LOW[MAXN],DFN[MAXN],head[MAXN],k,l,n,m,dfs_num,num,pre[MAXN],ans[MAXN],x,y;

int A[MAXN],B[MAXN],tmp[MAXN];

bool vis[MAXN],cnt[MAXN];

struct Edge{
    int from,to,next,num;
}E[MAXN<<2];

void Add(int from,int to)
{
    E[++num].from=from;
    E[num].to=to;
    E[num].num=num;
    E[num].next=head[from];
    head[from]=num;
}

void tarjan(int u,int fa)
{
    vis[u]=1,LOW[u]=DFN[u]=++dfs_num;
    for(int i=head[u];i;i=E[i].next)
    {
        int to=E[i].to;
        if(to==fa)  continue;
        if(!DFN[to])
        {
            tarjan(to,u);
            if(LOW[to]>DFN[u])  cnt[E[i].num]=1;
            LOW[u]=min(LOW[u],LOW[to]);
        }
        else LOW[u]=min(LOW[u],DFN[to]);
    }
}

void dfs(int u,int fa)
{
    vis[u]=1,DFN[u]=DFN[fa]+1;
    for(int i=head[u];i;i=E[i].next)
    {
        int to=E[i].to;
        if(to==fa||vis[to]) continue;
        dfs(to,u);
        A[u]+=A[to];
        B[u]+=B[to];
    }
}

int main()
{
    scanf("%d%d%d%d",&n,&m,&k,&l);

    for(int i=1;i<=k;i++)
    {
        scanf("%d",&x);
        A[x]++;
    }

    for(int i=1;i<=l;i++)
    {
        scanf("%d",&x);
        B[x]++;
    }

    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        Add(x,y),Add(y,x);
    }

    for(int i=1;i<=n;i++)
        if(!DFN[i]) tarjan(i,-1);

    for(int i=1;i<=num;i++)
        if(cnt[i])  tmp[++tmp[0]]=i;

    memset(DFN,0,sizeof DFN);
    memset(vis,0,sizeof vis);   
    dfs(1,-1);

    for(int i=1;i<=tmp[0];i++)
    {
        int v=E[tmp[i]].to,u=E[tmp[i]].from;
        if(DFN[v]<DFN[u])   swap(u,v);
        if(A[v]==0||B[v]==0||A[v]==k||B[v]==l)
            ans[++ans[0]]=tmp[i];
    }
    printf("%d\n",ans[0]);
    for(int i=1;i<=ans[0];i++)
        printf("%d\n",(ans[i]+1)/2);
    return 0;
}
  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值