• [Ahoi2005]LANE 航线规划


    题目描述

    对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系——一个巨大的由千百万星球构成的Samuel星系。 星际空间站的Samuel II巨型计算机经过长期探测,已经锁定了Samuel星系中许多星球的空间坐标,并对这些星球从1开始编号1、2、3……。 一些先遣飞船已经出发,在星球之间开辟探险航线。 探险航线是双向的,例如从1号星球到3号星球开辟探险航线,那么从3号星球到1号星球也可以使用这条航线。 例如下图所示:  在5个星球之间,有5条探险航线。 A、B两星球之间,如果某条航线不存在,就无法从A星球抵达B星球,我们则称这条航线为关键航线。 显然上图中,1号与5号星球之间的关键航线有1条:即为4-5航线。 然而,在宇宙中一些未知的磁暴和行星的冲撞,使得已有的某些航线被破坏,随着越来越多的航线被破坏,探险飞船又不能及时回复这些航线,可见两个星球之间的关键航线会越来越多。 假设在上图中,航线4-2(从4号星球到2号星球)被破坏。此时,1号与5号星球之间的关键航线就有3条:1-3,3-4,4-5。 小联的任务是,不断关注航线被破坏的情况,并随时给出两个星球之间的关键航线数目。现在请你帮助完成。

    输入

    第一行有两个整数N,M。表示有N个星球(1< N < 30000),初始时已经有M条航线(1 < M < 100000)。随后有M行,每行有两个不相同的整数A、B表示在星球A与B之间存在一条航线。接下来每行有三个整数C、A、B。C为1表示询问当前星球A和星球B之间有多少条关键航线;C为0表示在星球A和星球B之间的航线被破坏,当后面再遇到C为1的情况时,表示询问航线被破坏后,关键路径的情况,且航线破坏后不可恢复; C为-1表示输入文件结束,这时该行没有A,B的值。被破坏的航线数目与询问的次数总和不超过40000。

    输出

    对每个C为1的询问,输出一行一个整数表示关键航线数目。 注意:我们保证无论航线如何被破坏,任意时刻任意两个星球都能够相互到达。在整个数据中,任意两个星球之间最多只可能存在一条直接的航线。

    样例输入

    5 5 1 2 1 3 3 4 4 5 4 2 1 1 5 0 4 2 1 5 1 -1

    样例输出

    1 3

    首先,题意是求动态图的两点桥数。

    将边删除会很麻烦,所以先将要删去的边去掉,形成最后的图。

    求边双联通分量,缩点,形成一棵树(一定是一棵树)树边为关键边。

    再根据数据加边,每加入一边,则形成一个环,则环上路不再为关键边,最后将答案逆序输出。

    加入边后,两点之间的路径中的关键边可用树剖和线段树维护。

    线段树中,1表是关键边,0表不是,维护和。每加入一边,求两点LCA,并将线段树相应区间归零(要做延迟表记)。查询就输出线段树相应区间的和

    注意细节,代码有点长

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<map>
    #include<set>
    using namespace std;
    struct Messi1
    {
        int next,to;
    }edge1[200001],edge2[200001];
    struct Messi2
    {
        int p,q,c;
    }a[100001],b[100001];
    int isbridge[200001],son[30001],size[30001],fa[30001],dep[30001],top[30001],pos[30001],tot,m;
    int head1[30001],head2[30001],num1,num2,dfn[30001],low[30001],dfscnt,sccno[30001],n,scccnt,ans[30001];
    int lazy[100001],c[100001],cx;
    typedef pair<int,int> dou;//定义数对
    set<dou> vis,vis2;//此处用set可节约内存,且方便。
    void add1(int u,int v)//原图
    {
        num1++;
        edge1[num1].next=head1[u];
        edge1[num1].to=v;
        head1[u]=num1;
    }
    void add2(int u,int v)//缩点后的图
    {
        num2++;
        edge2[num2].next=head2[u];
        edge2[num2].to=v;
        head2[u]=num2;
    }
    void tarjan(int x,int fa)
    {int i;
        dfn[x]=low[x]=++dfscnt;
        int child=0;
        for (i=head1[x]; i; i=edge1[i].next)
        {
            int v=edge1[i].to;
            if (dfn[v]==0)
            {
                child++;
                tarjan(v,x);
                low[x]=min(low[x],low[v]);
                if (dfn[x]<low[v]) isbridge[i]=1;
            }
            else if (v!=fa) low[x]=min(low[x],dfn[v]);
        }
    }
    void dfs(int x,int v)
    {int i;
      //cout<<x<<' '<<v<<endl;
        dfn[x]=1;
        sccno[x]=v;
        for (i=head1[x]; i; i=edge1[i].next)
            if (isbridge[i]==0&&dfn[edge1[i].to]==0)
            {
                dfs(edge1[i].to,v);
            }
    }
    void make_tree()
    {int i,j,x1,y1;
        tarjan(1,-1);
        memset(dfn,0,sizeof(dfn));
        for (i=1; i<=n; i++)
            if (dfn[i]==0)
            {
                scccnt++;
                dfs(i,scccnt);
            }
        for (i=1; i<=n; i++)
        {
            for (j=head1[i]; j; j=edge1[j].next)
            {
                int v=edge1[j].to;
                if (sccno[i]!=sccno[v])
                {if (sccno[i]>sccno[v]) x1=sccno[v],y1=sccno[i];
                else y1=sccno[v],x1=sccno[i];
                    if (vis2.find(make_pair(x1,y1))==vis2.end())
                   //注:set的find函数返回指针,不存在时反回最后节点子节点,
                    所以不能写!find()。用end函数反回最后节点子节点
                    {
                        add2(x1,y1);
                        add2(y1,x1);
                        vis2.insert(make_pair(x1,y1));
                    }
                }
            }
        }
    }
    void dfs1(int u,int pa,int depth)
    {
        son[u]=0;
        size[u]=1;
        fa[u]=pa;
        dep[u]=depth;
        for (int j=head2[u]; j; j=edge2[j].next)
        {
            int v=edge2[j].to;
            if (v!=pa)
            {
                dfs1(v,u,depth+1);
                size[u]+=size[v];
                if (size[v]>size[son[u]]) son[u]=v;
            }
        }
    }
    void dfs2(int u,int tp)
    {
        top[u]=tp;
        pos[u]=++tot;
        if (son[u]) dfs2(son[u],tp);
        for (int j=head2[u]; j; j=edge2[j].next)
            if (edge2[j].to!=son[u]&&edge2[j].to!=fa[u])
            {
                dfs2(edge2[j].to,edge2[j].to);
            }
    }
    void pushdown(int rt)
    {
        if (lazy[rt])
        {
            c[rt*2]=0;
            lazy[rt*2]=1;
            c[rt*2+1]=0;
            lazy[rt*2+1]=1;
            lazy[rt]=0;
        }
    }
    int ask(int rt,int l,int r,int L,int R)
    {
        if (l!=r) pushdown(rt);
        if (l>=L&&r<=R)
        {
            return c[rt];
        }
         pushdown(rt);
         int mid=(l+r)/2,s=0;
         if (L<=mid) s+=ask(rt*2,l,mid,L,R);
         if (R>mid) s+=ask(rt*2+1,mid+1,r,L,R);
        return s;
    }
    int query(int x,int y)
    {
        int s=0;
        while (top[x]!=top[y])
        {
            if (dep[top[x]]<dep[top[y]]) swap(x,y);
            s+=ask(1,2,n,pos[top[x]],pos[x]);
            x=fa[top[x]];
        }
        if (dep[x]>dep[y]) swap(x,y);
        if (x!=y) s+=ask(1,2,n,pos[x]+1,pos[y]);
            return s;
    }
    void update(int rt,int l,int r,int L,int R)
    {
        if (l!=r)pushdown(rt);
        if (l>=L&&r<=R)
        {
            c[rt]=0;
            lazy[rt]=1;
            return;
        }
        pushdown(rt);
        int mid=(l+r)/2;
        if (L<=mid) update(rt*2,l,mid,L,R);
        if (R>mid) update(rt*2+1,mid+1,r,L,R);
        c[rt]=c[rt*2]+c[rt*2+1];
    }
    void change(int x,int y)
    {
        while (top[x]!=top[y])
        {
            if (dep[top[x]]<dep[top[y]]) swap(x,y);
            update(1,2,n,pos[top[x]],pos[x]);
            x=fa[top[x]];
        }
        if (dep[x]>dep[y]) swap(x,y);
        if (x!=y) update(1,2,n,pos[x]+1,pos[y]);
        }
    void build(int rt,int l,int r)
    {
        if (l==r)
        {
            c[rt]=1;
            return;
        }
        int mid=(l+r)/2;
        build(rt*2,l,mid);
        build(rt*2+1,mid+1,r);
        c[rt]=c[rt*2]+c[rt*2+1];
    }
    int main()
    {int i,j,x,y;
    //freopen("lane.in","r",stdin);
    //freopen("lane.out","w",stdout);
        cin>>n>>m;
        for (i=1; i<=m; i++)
        {
            scanf("%d%d",&a[i].p,&a[i].q);
            vis.insert(make_pair(a[i].p,a[i].q));
        }
        int tot1=0;
        scanf("%d",&cx);
        while (cx!=-1)
        {
            scanf("%d%d",&x,&y);
            if (cx==0)
            {
                tot1++;
                b[tot1].p=x;
                b[tot1].q=y;
                b[tot1].c=0;
                vis.erase(make_pair(x,y));
            }
            else
            {
                tot1++;
                b[tot1].c=1;
                b[tot1].p=x;
                b[tot1].q=y;
            }
            scanf("%d",&cx);
        }
        for (i=1; i<=m; i++)
        {
            if (vis.find(make_pair(a[i].p,a[i].q))!=vis.end())
            {
                add1(a[i].p,a[i].q);
                add1(a[i].q,a[i].p);
            }
        }
        make_tree();
        dfs1(1,1,1);
        dfs2(1,1);
        n=scccnt;
        //cout<<scccnt<<endl;
        build(1,2,n);
        memset(ans,-1,sizeof(ans));
        for (i=tot1; i>=1; i--)
        {
            if (b[i].c==0)
            {
                int u=sccno[b[i].p],v=sccno[b[i].q];
                change(u,v);
            }
            else
            {
                int u=sccno[b[i].p],v=sccno[b[i].q];
                ans[i]=query(u,v);
            }
        }
        for (i=1; i<=tot1; i++)
            if (ans[i]!=-1) printf("%d
    ",ans[i]);
    }
  • 相关阅读:
    设计模式-14-桥接模式
    设计模式-13-中介者模式
    设计模式-12-命令模式
    设计模式-11-外观模式
    设计模式-10-装饰器
    设计模式-9-模板
    设计模式-8-适配器模式-组合
    设计模式-8-适配器模式-继承
    设计模式-7-策略模式+工厂模式
    设计模式-7-策略模式
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/7048353.html
Copyright © 2020-2023  润新知