CF2132F 解题报告

CF2132F 解题报告

简要题意

给出 \(n\) 个点 \(m\) 条边的无向连通图,询问 \(q\) 次。每次询问需要回答对于一个点 \(x\),在“从 \(1\)\(n\) 必须经过的边”中和 \(x\) 距离最小的边的编号(如果有多个,取编号最小)。

数据范围:保证所有输入数字均为不超过 \(2 \times 10^5\) 的正整数。

分析

“必须经过的边”就是指割边

那么题目转化为求 \(1\)\(n\) 所有路径构成的图上的割边。

我们考虑先找到这张图上的点,这可以用两次 dfs 实现。

具体地,在这个图上的点一定可以在从 \(n\) 通过 dfs 访问到 \(1\) 的过程中被访问到。但是只 dfs 一次会有一种情况:在这张图上的一个环中有一个点 \(u\),访问到了它在 dfs 生成树上的父亲 \(v\)。但是此时还没有回溯到 \(v\),因此 \(v\) 是没有被打标记的,所以 \(u\) 打不上不标记。因此我们需要再 dfs 一次,来确保所有点都被打上了标记。

然后就是正常求割边。最后就 bfs 求出每一个点的答案即可。

代码

const int N=2e5+100;
int T,n,m,k,cnt;
struct Edge{int from,to,id;}e[N<<1];
int num,h[N];
void add(int f,int t,int d){e[++num].from=h[f],e[num].to=t,e[num].id=d,h[f]=num;}
int dfn[N],low[N],vis[N],dfu;
bool able[N],vis1[N];
bool dfs(int u,int fa){
    vis1[u]=true;
    if(u==1) return able[u]=true;
    for(int i=h[u];i;i=e[i].from){
        int v=e[i].to;
        if(v==fa) continue;
        if(vis1[v]){able[u]|=able[v];continue;}
        able[u]|=dfs(v,u);
    }
    return able[u];
}
void tarjan(int u,int fa){
    low[u]=dfn[u]=++dfu;
    for(int i=h[u];i;i=e[i].from){
        int v=e[i].to;
        if(v==fa || !able[v]) continue;
        if(!dfn[v]){
            tarjan(v,u);
            low[u]=min(low[u],low[v]);
            if(low[v]>dfn[u])
                ckmn(vis[v],e[i].id),ckmn(vis[u],e[i].id);
        }
        else
            low[u]=min(low[u],dfn[v]);
    }
}
pii lst[N];
queue<pii> q;
void solve(){
    n=read(),m=read();
    For(i,1,n) h[i]=dfn[i]=low[i]=able[i]=vis1[i]=0,vis[i]=inf;
    num=dfu=cnt=0;
    int u,v;
    For(i,1,m) u=read(),v=read(),add(u,v,i),add(v,u,i);
    dfs(n,0);
    For(i,1,n) vis1[i]=0;
    dfs(n,0);
    tarjan(1,0);
    //For(i,1,n) printf("%d ",vis[i]);
    //putchar('\n');
    For(i,1,n)
        if(vis[i]!=inf)
            lst[++cnt]=make_pair(vis[i],i);
    sort(lst+1,lst+cnt+1,less<pii>());
    For(i,1,cnt) q.push(lst[i]);
    while(!q.empty()){
        int p=q.front().first,u=q.front().second;q.pop();
        for(int i=h[u];i;i=e[i].from){
            int v=e[i].to;
            if(vis[v]!=inf) continue;
            vis[v]=p;
            q.push(make_pair(p,v));
        }
    }
    k=read();
    For(i,1,k)
        u=read(),printf("%d ",vis[u]==inf ? -1 : vis[u]);
    putchar('\n');
}
posted @ 2025-09-07 16:36  XiaoZi_qwq  阅读(12)  评论(0)    收藏  举报