• Traffic Real Time Query System,题解


    题目链接

    题意:

      问从一条边到另一条边的必经点。

    分析:

      首先,问必经点,当然是要点双缩点(圆方树)啦,关键是把边映射到哪一点上,其实直接放在某联通分量的方点上就行,但是这个点并不好找,所以我们考虑一个别的办法。

      我们这样去考虑,如果这个边连着的有一个点不是割点,那么就直接给它找到方点就行了,但是如果是割点呢?那么我们就找一次所有的与这两个点相邻的方点,然后找到就好了,但是这样的复杂度我们并不喜欢,我们可以考虑换一种想法,有了圆方树之后,我们要找路径间的圆点的个数,其实你想一想,如果以圆点开头圆点结尾就可以直接根据总点数求出(当然不这样写也行),然后就是开始配对,边1连接的两点和边2连接的两点相配,分别求出路径上圆点的个数(不包括起点和终点),答案是什么呢?取max,为啥,因为都不包括起点和终点,为了防止某点为割点(+1并不行,是割点不一定就要过),我们只能进行取max,然后4次lca,最后找出答案。

      代码:

    #include <cstdio>
    #include <string>
    #include <cstring>
    using namespace std;
    const int maxn=2e4+10;
    const int maxm=1e5+10;
    struct E{
        int to;
        int next;
        int from;
    }ed[maxm*2];
    int head[maxn];
    int tot;
    void J(int a,int b){
        tot++;
        ed[tot].to=b;
        ed[tot].from=a;
        ed[tot].next=head[a];
        head[a]=tot;
    }
    int dfn[maxn];
    int low[maxn];
    int sta[maxn];
    int top;
    int js;
    int s;
    int n;
    E edx[maxn*2];
    int headx[maxn];
    int totx;
    void Jx(int a,int b){
        totx++;
        edx[totx].to=b;
        edx[totx].next=headx[a];
        headx[a]=totx;
    }
    void tarjan(int x){//缩点
        js++;
        low[x]=dfn[x]=js;
        top++;
        sta[top]=x;
        for(int i=head[x];i;i=ed[i].next){
            if(dfn[ed[i].to])
                low[x]=min(low[x],dfn[ed[i].to]);
            else{
                tarjan(ed[i].to);
                low[x]=min(low[ed[i].to],low[x]);
                if(low[ed[i].to]==dfn[x]){
                    s++;
                    int tmp;
                    do{
                        tmp=sta[top];
                        top--;
                        Jx(n+s,tmp);
                        Jx(tmp,s+n);
                    }while(tmp!=ed[i].to);
                    Jx(x,n+s);
                    Jx(n+s,x);
                }
            }
        }
    }
    int vis[maxn];
    int dep[maxn];
    int fa[maxn];
    void Dfs(int x){
        vis[x]=1;
        for(int i=headx[x];i;i=edx[i].next){
            if(vis[edx[i].to])
                continue;
            dep[edx[i].to]=dep[x]+1;
            fa[edx[i].to]=x;
            Dfs(edx[i].to);
        }
    }
    int lc(int a,int b){//lca
        if(dep[a]<dep[b])
            swap(a,b);
        while(dep[a]>dep[b])
            a=fa[a];
        if(a==b)
            return a;
        while(a!=b){
            a=fa[a];
            b=fa[b];
        }
        return a;
    }
    int l(int a,int b){
        return (dep[a]+dep[b]-2*dep[lc(a,b)])/2-1;
    }
    int main(){
        int m;
        while(~scanf("%d%d",&n,&m)&&(m||n)){
            tot=0;
            memset(head,0,sizeof(head));
            totx=0;
            memset(headx,0,sizeof(headx));
            int js1,js2;
            js=0;
            memset(dfn,0,sizeof(dfn));
            top=0;
            s=0;
            memset(vis,0,sizeof(vis));
            for(int i=1;i<=m;i++){
                scanf("%d%d",&js1,&js2);
                J(js1,js2);
                J(js2,js1);
            }
            for(int i=1;i<=n;i++)
                if(!dfn[i])
                    tarjan(i);
            for(int i=1;i<=n+s;i++)
                if(!vis[i])
                    Dfs(i);
            int q;
            scanf("%d",&q);
            for(int i=1;i<=q;i++){
                scanf("%d%d",&js1,&js2);
                printf("%d
    ",max(max(l(ed[js1*2].to,ed[js2*2].to),l(ed[js1*2].from,ed[js2*2].to)),max(l(ed[js1*2].to,ed[js2*2].from),l(ed[js1*2].from,ed[js2*2].from))));//分别计算
            }
        }
        return 0;
    }
  • 相关阅读:
    postgresql遇到的性能问题
    面试(三)
    Oracle的dmp文件的导入
    plsql的参数IN和OUT
    IT小说
    被关注应该也是一种强大-日经某文有感
    总结:安卓手机页面样式没问题,苹果手机样式错乱。
    前端开发人员要注意的css规范,css命名。
    水平,垂直居中的15种方法
    nuxt 的一些报错和插件推荐
  • 原文地址:https://www.cnblogs.com/wish-all-ac/p/12830180.html
Copyright © 2020-2023  润新知