hdu4338 Simple Path

步骤:tarjan求割点,tarjan求点双连通分量并建图,对得到的森林进行dfs求出两个量sum[i]和dis[i],tarjan离线求LCA。

#pragma comment(linker, "/STACK:102400000,102400000")

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
const int maxn=100005;
struct edge
{
    int to,next;
}oee[maxn*4],ee[maxn*8];
int oe[maxn],e[maxn*2],ecnt,oecnt;
int n;
void addedge1(int u,int v)
{
    oee[oecnt].to=v;oee[oecnt].next=oe[u];oe[u]=oecnt++;
    oee[oecnt].to=u;oee[oecnt].next=oe[v];oe[v]=oecnt++;
}
void addedge2(int u,int v)
{
    ee[ecnt].to=v;ee[ecnt].next=e[u];e[u]=ecnt++;
    ee[ecnt].to=u;ee[ecnt].next=e[v];e[v]=ecnt++;
}
void edgeinit()
{
    memset(oe,-1,sizeof(oe));oecnt=0;
    memset(e,-1,sizeof(e));ecnt=0;
}
int size[maxn*2],id[maxn],idcnt;
void init0()
{
    memset(size,0,sizeof(size));
    int i;
    for(i=1;i<=n;++i)
        id[i]=-i;
    idcnt=0;
}
//求割点
int dfn1[maxn*2],low1[maxn*2],ind1;
bool cid[maxn];
void tarjan1(int f,int u,bool flag)
{
    dfn1[u]=low1[u]=++ind1;
    int i,j,v,cnt=0;
    for(i=oe[u];i!=-1;i=oee[i].next)
    {
        v=oee[i].to;
        if(v==f)
            continue;
        if(dfn1[v]!=-1)
        {
            low1[u]=min(low1[u],dfn1[v]);
        }
        else
        {
            cnt++;
            tarjan1(u,v,false);
            low1[u]=min(low1[u],low1[v]);
            if(dfn1[u]<=low1[v]&&flag==false)
            {
                if(cid[u]==false)
                {
                    cid[u]=true;
                    id[u]=++idcnt;
                    size[idcnt]=1;
                }
            }
        }
    }
    if(flag&&cnt>1)
    {
        if(cid[u]==false)
        {
            cid[u]=true;
            id[u]=++idcnt;
            size[idcnt]=1;
        }
    }
}
void work1()
{
    memset(dfn1,-1,sizeof(dfn1));
    memset(low1,-1,sizeof(low1));
    ind1=0;
    memset(cid,false,sizeof(cid));
    int i;
    for(i=1;i<=n;++i)
    {
        if(dfn1[i]==-1)
        {
            tarjan1(-1,i,true);
        }
    }
}
//求双连通分量
stack<int> stk2;
int dfn2[maxn*2],low2[maxn*2],ind2;
void tarjan2(int f,int u)
{
    dfn2[u]=low2[u]=++ind2;
    stk2.push(u);
    int i,v,tv;
    for(i=oe[u];i!=-1;i=oee[i].next)
    {
        v=oee[i].to;
        if(v==f)
            continue;
        if(dfn2[v]!=-1)
        {
            low2[u]=min(low2[u],dfn2[v]);
        }
        else
        {
            tarjan2(u,v);
            low2[u]=min(low2[u],low2[v]);
            if(dfn2[u]<=low2[v])
            {
                idcnt++;
                do
                {
                    tv=stk2.top();stk2.pop();
                    size[idcnt]++;
                    if(cid[tv])
                    {
                        addedge2(idcnt,id[tv]);
                    }
                    else
                    {
                        id[tv]=idcnt;
                    }
                }while(tv!=v);
                size[idcnt]++;
                if(cid[u])
                    addedge2(idcnt,id[u]);
                else
                    id[u]=idcnt;
            }
        }
    }
}
void work2()
{
    while(!stk2.empty())
        stk2.pop();
    memset(dfn2,-1,sizeof(dfn2));
    memset(low2,-1,sizeof(low2));
    ind2=0;
    int i;
    for(i=1;i<=n;++i)
        if(dfn2[i]==-1)
            tarjan2(-1,i);
}
//新图中dfs预处理出dis和sum 每个点距离树根的距离以及点数和
int dis3[maxn*2],sum3[maxn*2];
void dfs3(int f,int u,int num,int d)
{
    dis3[u]=d;sum3[u]=num+size[u];
    int i,v;
    for(i=e[u];i!=-1;i=ee[i].next)
    {
        v=ee[i].to;
        if(v==f)
            continue;
        dfs3(u,v,sum3[u],d+1);
    }
}
void work3()
{
    memset(dis3,-1,sizeof(dis3));
    memset(sum3,0,sizeof(sum3));
    int i;
    for(i=1;i<=idcnt;++i)
    {
        if(dis3[i]==-1)
        {
            dfs3(-1,i,0,0);
        }
    }
}
//tarjan 离线求LCA
struct ord
{
    int ans,lab;
    ord(){}
    ord(int a,int l)
    {
        ans=a,lab=l;
    }
};
bool cmp(const ord &a,const ord &b)
{
    return a.lab<b.lab;
}
struct need
{
    int v,lab;
    need(){}
    need(int a,int b)
    {
        v=a;lab=b;
    }
};
vector<ord> v1;
vector<need> v2[maxn*2];
int f1[maxn],f2[maxn*2];
int col[maxn*2];
bool hash[maxn];
int find(int x)
{
    if(f2[x]==x)
        return x;
    else
        return f2[x]=find(f2[x]);
}
void dfs44(int f,int u,int idd)
{
    hash[u]=true;
    f1[u]=idd;
    int i,v;
    for(i=oe[u];i!=-1;i=oee[i].next)
    {
        v=oee[i].to;
        if(hash[v])
            continue;
        dfs44(u,v,idd);
    }
}
void tarjan4(int f,int u)
{
    int i,v,l,tans,lca;
    f2[u]=u;col[u]=1;
    for(i=e[u];i!=-1;i=ee[i].next)
    {
        v=ee[i].to;
        if(v==f)
            continue;
        if(col[v]==0)
        {
            tarjan4(u,v);
            f2[v]=u;
        }
    }
    for(i=0;i<v2[u].size();++i)
    {
        v=v2[u][i].v;l=v2[u][i].lab;
        if(col[v]==2)
        {
            lca=find(v);
            tans=sum3[u]+sum3[v]-2*sum3[lca]+size[lca]-dis3[u]-dis3[v]+2*dis3[lca];
            v1.push_back(ord(n-tans,l));
        }
    }
    col[u]=2;
}
void work4(int cas)
{
    v1.clear();
    int i,iddd=0,u,v,idddd=0;
    for(i=1;i<=idcnt;++i)
        v2[i].clear();
    for(i=1;i<=n;++i)
        f1[i]=-i;
    for(i=1;i<=maxn*2;++i)
        f2[i]=i;
    memset(hash,false,sizeof(hash));
    memset(col,0,sizeof(col));
    for(i=1;i<=n;++i)
        if(hash[i]==false)
        {
            dfs44(-1,i,++iddd);
        }
    int k;
    scanf("%d",&k);
    while(k--)
    {
        idddd++;
        scanf("%d%d",&u,&v);
        u++;v++;
        if(u==v)
        {
            v1.push_back(ord(n-1,idddd));
            continue;
        }
        if(f1[u]!=f1[v])
        {
            v1.push_back(ord(n,idddd));
            continue;
        }
        if(id[u]!=id[v])
        {
            v2[id[u]].push_back(need(id[v],idddd));
            v2[id[v]].push_back(need(id[u],idddd));
            continue;
        }
        if(id[u]==id[v])
        {
            v1.push_back(ord(n-size[id[u]],idddd));
            continue;
        }
    }
    for(i=1;i<=idcnt;++i)
    {
        if(col[i]==0)
        {
            tarjan4(-1,i);
        }
    }
    sort(v1.begin(),v1.end(),cmp);
    printf("Case #%d:\n",cas);
    for(i=0;i<v1.size();++i)
    {
        printf("%d\n",v1[i].ans);
    }
    printf("\n");
}
int main()
{
    int i,j,u,v,m,cas=0;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        edgeinit();
        while(m--)
        {
            scanf("%d%d",&u,&v);
            u++;v++;
            addedge1(u,v);
        }
        init0();
        work1();
        work2();
        work3();
        ++cas;
        work4(cas);
    }
    return 0;
}




 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值