QOJ.ac

QOJ

Type: Editorial

Status: Open

Posted by: robertfan

Posted at: 2026-04-16 11:30:15

Last updated: 2026-04-16 11:31:33

Back to Problem

New Editorial for Problem #837

A

如果图是一棵树,那么可以考虑离线点分治解决。

具体的,在每一个点处计算经过这个点的路径的距离,则对于每一个点,有一个深度,那么答案变为加入一个 $dep$ 和询问是否存在一个 $dep$ 满足 $DEP+dep<=x$ 。

可以直接记录dep的最小值,之后如果不经过分治中心,就划归为子问题,接下来考虑图的情况。

显然有一个跨过 $i$ 的返祖边就代表 $i$ 在一个简单环中,所以跨过每个点的返祖边的个数都 $\leq k$。

此时一个最短路要么经过树上路径的分治中心 $C$,要么经过 跨过 $C$ 的全部非树边的端点(不然到不了其他子树)。

于是对于每一个关键点,将 $dep_u$ 变为 $u$ 到关键点的最短路即可同理做完,对于以上的 $O(k)$ 个点计算答案即可。

#include <bits/stdc++.h>
using namespace std;
vector<int>g[100005],T[100005];
bool vis[100005];
void dfs(int u,int f){
    vis[u]=1;
    for(int v:g[u]){
        if(v==f)continue;
        if(!vis[v]){
            dfs(v,u);
            T[u].push_back(v);
            T[v].push_back(u);
        }
    }
}
int sz[100005],rt,all;
void findrt(int u,int f){
    sz[u]=1;
    int mx=0;
    for(int v:T[u]){
        if(v==f||vis[v])continue;
        findrt(v,u);
        sz[u]+=sz[v];
        mx=max(mx,sz[v]);
    }
    mx=max(mx,all-sz[u]);
    if(mx+mx<=all){
        rt=u;
    }
}
int bel[100005],ins[100005];
vector<int>P;
void divide(int u,int f,int tp,int typ){
    sz[u]=1;
    bel[u]=tp;
    ins[u]=typ;
    P.push_back(u);
    for(int v:T[u]){
        if(v==f||vis[v])continue;
        divide(v,u,f==0?v:tp,typ);
        sz[u]+=sz[v];
    }
}
int dis[100005];
void sou(int x,int typ){
    dis[0]=1e9;
    for(int u:P){
        dis[u]=1e9;
    }
    // memset(dis,0x3f,sizeof(dis));
    queue<int>q;
    q.push(x);
    dis[x]=0;
    while(q.size()){
        int u=q.front();
        q.pop();
        for(int v:g[u]){
            if(0==vis[v]&&ins[v]==typ&&dis[v]==dis[0]){
                dis[v]=dis[u]+1;
                q.push(v);
            }
        }
    }
}
int ans[200005];
vector<tuple<int,int,int> >vec[100005];
void solve(int u,vector<tuple<int,int,int> >ve){
    P.clear();
    divide(u,0,u,u);
    vector<int>pnt;
    for(int v:P){
        if(v==u)continue;
        for(int w:g[v]){
            if(ins[w]==u&&w!=u)
                if(bel[v]!=bel[w]){
                    pnt.push_back(w);
                }
        }
    }
    pnt.push_back(u);
    for(int a:pnt){
        sou(a,u);
        int mnd=1e9;
        for(auto [tp,val,id]:ve){
            if(tp==1){
                mnd=min(mnd,dis[val]);
            }else{
                ans[id]=min(ans[id],dis[val]+mnd);
            }
        }
    }
    for(auto [tp,val,id]:ve){
        if(val!=u){
            vec[bel[val]].push_back({tp,val,id});
        }
    }
    vis[u]=1;
    for(int v:T[u]){
        if(vis[v])continue;
        all=sz[v];
        findrt(v,u);
        vector<tuple<int,int,int> >tmp=vec[v];
        vec[v].clear();
        solve(rt,tmp);
    }
}
int main(){
    int n,m,k;
    cin>>n>>m>>k;
    for(int i=1;i<=m;i++){
        int u,v;
        cin>>u>>v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    dfs(1,0);
    vector<tuple<int,int,int> >ve;
    int q;;
    cin>>q;
    for(int i=1;i<=q;i++){
        int tp,val;
        cin>>tp>>val;
        ve.push_back({tp,val,i});
    }
    memset(ans,0x3f,sizeof(ans));
    memset(vis,0,sizeof(vis));
    all=n;
    findrt(1,0);
    solve(rt,ve);
    for(int i=1;i<=q;i++){
        if(ans[i]<1e9){
            cout<<ans[i]<<'\n';
        }
    }
}

Comments

No comments yet.