poj3694 Network 边双联通缩点+离线LCA

来源:互联网 发布:linux中tar命令 编辑:程序博客网 时间:2024/04/26 06:16

      给一个联通的图,然后依次添加Q条边,每次添加边之后,图中还剩多少条桥?先求一下边双联通重构成一棵树,然后就是求LCA了,查询的时候从两个点开始往祖先一边爬一边标记掉沿途的边,根据每次标记掉的点以及上一次的答案就可以递推出当前的答案...切记一点这题有重边...所以求ebc的时候记得用边判父节点...思路不是很难,但代码写起来太坑爹了......

#include <iostream>#include <cstdio>#include <algorithm>#include <cmath>#include <cstring>#include <vector>#include <stack>using namespace std;typedef long long ll;const int maxn=155000;struct EDGE{    int v,w,next;}ed1[maxn<<2],ed2[maxn<<2],ed3[4040];int g[maxn];int gg[maxn];int qe[maxn];int p1,p2,p3;stack<int> s;int pre[maxn];int id[maxn],dfs_clock,ebc_cnt;int deg[maxn];bool ok[maxn];int n,m,k,p,q;int dfs(int u,int frm){    int lowu=pre[u]=++dfs_clock;    s.push(u);    for (int j=g[u];j!=-1; j=ed1[j].next)    {        int v=ed1[j].v;        if (j==(frm^1)) continue;        if (!pre[v])        {            int lowv=dfs(v,j);            lowu=min(lowu,lowv);        }        else if (pre[v]<pre[u])        {            lowu=min(lowu,pre[v]);        }    }    if (lowu==pre[u])    {        ebc_cnt++;        while (true)        {            int x=s.top();            s.pop();            id[x]=ebc_cnt;            if (x==u) break;        }    }    return lowu;}void findebc(int n){    memset(pre,0,sizeof pre);    memset(id,0,sizeof id);    while(!s.empty()) s.pop();    for (int i=1; i<=n; i++)    {        if (!pre[i]) dfs(i,-1);    }}int dis[maxn];bool vis[maxn];int fa[maxn];int res[maxn][3];int fr[maxn];int find(int x){    if (x==fa[x]) return fa[x];    return fa[x]=find(fa[x]);}void lca(int u){    vis[u]=true;    fa[u]=u;    int v;    for (int j=qe[u]; j!=-1; j=ed3[j].next)    {        v=ed3[j].v;        if (vis[v])        {            res[ed3[j].w][2]=find(v);        }    }    for (int j=gg[u]; j!=-1; j=ed2[j].next)    {        v=ed2[j].v;        if (!vis[v])        {            fr[v]=u;            dis[v]=dis[u]+1;            lca(v);            fa[v]=u;        }    }}int ans[maxn];int main(){//    freopen("in.txt","r",stdin);    int x,y;    int cp=0;    while(~scanf("%d%d",&n,&m))    {        if (n==0 && m==0) break;        cp++;        printf("Case %d:\n",cp);        memset(g,-1,sizeof g);        memset(gg,-1,sizeof gg);        memset(qe,-1,sizeof qe);        p1=p2=p3=0;        for (int i=1; i<=m; i++)        {            scanf("%d%d",&x,&y);            ed1[p1].v=y;            ed1[p1].w=1;            ed1[p1].next=g[x];            g[x]=p1;            p1++;            ed1[p1].v=x;            ed1[p1].w=1;            ed1[p1].next=g[y];            g[y]=p1;            p1++;        }        ebc_cnt=0;        findebc(n);        for (int i=1; i<=n; i++)            for (int j=g[i]; j!=-1; j=ed1[j].next)            {                x=id[i];                y=id[ed1[j].v];                if (x!=y)                {                    ed2[p2].v=y;                    ed2[p2].w=1;                    ed2[p2].next=gg[x];                    gg[x]=p2;                    p2++;                    ed2[p2].v=x;                    ed2[p2].w=1;                    ed2[p2].next=gg[y];                    gg[y]=p2;                    p2++;                }            }        int sum=ebc_cnt-1;        memset(vis,false,sizeof vis);        memset(res,0,sizeof res);        scanf("%d",&q);        for (int i=1; i<=q; i++)        {            scanf("%d%d",&x,&y);            x=id[x];            y=id[y];            ed3[p3].v=y;            ed3[p3].w=i;            ed3[p3].next=qe[x];            qe[x]=p3;            p3++;            ed3[p3].v=x;            ed3[p3].w=i;            ed3[p3].next=qe[y];            qe[y]=p3;            p3++;            res[i][0]=x;            res[i][1]=y;        }        dis[0]=0;        lca(1);        memset(ans,0,sizeof ans);        memset(ok,false,sizeof ok);        ans[0]=sum;        for (int i=1; i<=q; i++)        {            x=res[i][0];            y=res[i][1];            int t=res[i][2];            ans[i]=ans[i-1];            while (x!=t)            {                if (!ok[x]) ans[i]--,ok[x]=true;                x=fr[x];            }            while (y!=t)            {                if (!ok[y]) ans[i]--,ok[y]=true;                y=fr[y];            }        }        for (int i=1; i<=q; i++)        printf("%d\n",ans[i]);        printf("\n");    }    return 0;}


0 0
原创粉丝点击