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)));
        }
    }
}

原文地址:https://www.cnblogs.com/Zfio/p/12842564.html