• UVA1464 Traffic Real Time Query System


    传送门:https://www.luogu.com.cn/problem/UVA1464

    看到这道题,求必经的点数,还是无向图。那么妥妥的圆方树。圆方树上的任意两圆点间的路径必定是圆点方点相交错的,对于树上的两点来说,必经的点数就是这两点间简单路径上的圆点的个数。那么这样问题就转化为求树上两点间经过的圆点的个数了。那么我们可以再加一个LCA来解决问题。对于两个圆点,它们的LCA一定是一个方点(当然一个是另一个的祖先时除外)。经过推导可以得出

    • ans=(dep[u]+dep[v]-2×dep[LCA(u,v)])/2-1;

    然后需要注意的地方就是整个图不一定是全连通的,以及题目中所给的起点终点是两条边,不是点,所以我们把四个顶点都算一遍取最大值。

    题本身难度不大,难度在于代码打不出来。。。

    代码调了一晚上没调出来结果是数组开小了。。。不说了,还是感谢lc大锅。

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<vector>
    #include<cmath>
    using namespace std;
    const int maxn=100000+1,maxm=300000+1;
    struct Edge{
        int next,to;
    }edge[maxn<<1];
    int head[maxn],len=1;
    void Add(int u,int v){
        edge[++len].next=head[u];
        edge[len].to=v;
        head[u]=len;
    }
    vector<int> G[maxn];
    int dfs_clock=0,sta[maxn],top=0,dfn[maxn],low[maxn];
    int belong[maxn],dcc_cnt;
    bool cut[maxn];
    
    void Tarjan(int u,int fa){
        dfn[u]=low[u]=++dfs_clock;
        sta[++top]=u;
        int son=0;
        for(int i=head[u];i;i=edge[i].next){
            int v=edge[i].to;
            if(!dfn[v]){
                son++;
                Tarjan(v,fa);
                low[u]=min(low[u],low[v]);
                if(dfn[u]<=low[v]){
                    if(u!=fa) cut[u]=1;//习惯性判了个割点,这里不判也没事
                    dcc_cnt++;
                    int x;
                    while(true){
                        x=sta[top--];
                        G[dcc_cnt].push_back(x);
                        G[x].push_back(dcc_cnt);
                        if(v==x) break;
                    }
                    G[dcc_cnt].push_back(u);//一个割点可能同属于多个点双,故不退栈,单独处理
                    G[u].push_back(dcc_cnt);
                }
            }
            else 
                low[u]=min(low[u],dfn[v]);
        }
        if(u==fa&&son>=2) cut[u]=1;//习惯性判了个割点,这里不判也没事
    }
    
    int f[maxn][30],dep[maxn];
    bool vis[maxn];
    
    void Dfs(int u,int fa){//有毒的倍增法求LCA
        dep[u]=dep[fa]+1;
        vis[u]=1;
        f[u][0]=fa;
        for(int i=1;(1<<i)<=dep[u];i++){
            f[u][i]=f[f[u][i-1]][i-1];
        }
        for(int i=0;i<G[u].size();i++){
            int v=G[u][i];
            if(v!=fa&&!vis[v]) Dfs(v,u);
        }
    }   
    
    int Lca(int s,int t){
        if(dep[s]>dep[t])swap(s,t);
        int d=dep[t]-dep[s];
        int k=0;
        while(d){
            if(d&1) t=f[t][k];
            k++;
            d>>=1;
        }
        if(s==t) return s;
        for(int i=20;i>=0;i--){
            if(f[s][i]!=f[t][i])
                s=f[s][i],t=f[t][i];
        }
        return f[s][0];
    }
    int from[maxn],to[maxn];
    void Del(int n){//多组数据,初始化
        memset(from,0,sizeof(from));
        memset(to,0,sizeof(to));
        memset(head,0,sizeof(head));
        len=0;
        memset(G,0,sizeof(G));
        memset(vis,0,sizeof(vis));
        memset(cut,0,sizeof(cut));
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(f,0,sizeof(f));
        memset(dep,0,sizeof(dep));
        dcc_cnt=n;//方点从n+1开始编号
        top=0;
        dfs_clock=0;
    }
    int Calc(int u,int v){
        return (dep[u]+dep[v]-(dep[Lca(u,v)]<<1))/2-1;
    }
    
    int solve(int xx,int yy){
        return (dep[xx]+dep[yy]-2*dep[Lca(xx,yy)])/2-1; 
    }
    
    int main(){
        int n,m;
        while(scanf("%d%d",&n,&m) && n!=0){
            if(n==0||m==0) return 0;
            Del(n);
            int u,v;
            for(int i=1;i<=m;i++){
                scanf("%d%d",&u,&v);
                Add(u,v);
                Add(v,u);
                from[i]=u,to[i]=v;
            }
            for(int i=1;i<=n;i++){
                if(!dfn[i])
                    Tarjan(i,i);
            }
            for(int i=1;i<=dcc_cnt;i++){
                if(!vis[i])
                    Dfs(i,0);
            }
            /*for(int i=1;i<=dcc_cnt;i++){
            	int u=G[i].size();
            	for(int j=0;j<u;j++){
            		printf("%d %d
    ",i,G[i][j]);
    			}
    		}*/
            int q;
            scanf("%d",&q);
            //printf("%d %d %d
    ",Lca(2,3),dep[2],dep[3]);
            for(int i=1;i<=q;i++){
                scanf("%d%d",&u,&v);
                int a1=from[u],a2=to[u],b1=from[v],b2=to[v];
                //printf("%d %d %d %d %d %d %d %d %d
    ",a1,dep[a1],a2,dep[a2],b1,dep[b1],b2,dep[b2],Lca(b1,b2));
                int a=solve(a1,b1),b=solve(a1,b2),c=solve(a2,b1),d=solve(a2,b2);//四个点都试一下
                //printf("%d %d %d %d
    ",a,b,c,d);
                //printf("%d %d %d
    ",a2,b1,Lca(a2,b1));
                printf("%d
    ",max(max(a,b),max(c,d)));
            }
        }
    }
    
    
  • 相关阅读:
    Linux部署springboot项目创建守护进程
    实现数据库安全性控制的方法和主要技术。
    推荐一些学习MySQL的资源
    带你解析MySQL binlog
    一文解决MySQL时区相关问题
    手把手教你看MySQL官方文档
    MySQL关于日期为零值的处理
    关于日期及时间字段的查询
    是时候学习Linux了
    MySQL分区表最佳实践
  • 原文地址:https://www.cnblogs.com/Zfio/p/12842564.html
Copyright © 2020-2023  润新知