头像

欢迎来到我的博客

分享题解与总结

P8805 机房

P8805 机房

P8805 机房 - 洛谷

题意

任意一点\(u\)的延迟时间 \(t=u的出边数量\)

对于一次询问,求出\(u\)\(v\)的总延迟时间

思路

建树vector<int> e[N]

统计每个点的出边数siz[i] = e[i].size()

统计前缀和数组 root->i总共出边数

  1. u==v 产生延迟siz[u]
  2. u!=v
    • lca(u,v)
    • answer=prefix[u]+prefix[v]-2*prefix[lca]+(lca的出边数)

注意:题目“发送方和接收方相同会产生一次延迟”,指的是产生siz[发送方]个时间的延迟,不是1个时间的延迟

图解

样例1

8 3
2 3 
2 4
3 1
3 5
4 6
5 7
5 8
3 6
7 5
1 8
8
4
8

屏幕截图 2026-08-16 113927

代码

const int N=1e5+5;
const int K=20;
int n,m;
vector<int> e[N];
int fa[N][21],depth[N];
ll siz[N],pre[N];

void dfs1(int x,int f,ll sz)//sum(root->f)的前缀和
{
    fa[x][0]=f;depth[x]=depth[f]+1;
    for(int i=1;i<=K;++i){
        fa[x][i]=fa[fa[x][i-1]][i-1];
    }
    pre[x]=sz+siz[x];

    for(int v:e[x]){
        if(v==f) continue;
        dfs1(v,x,pre[x]);
    }
}

int LCA(int x,int y)
{
    if(depth[x]<depth[y]) swap(x,y);
    for(int i=K;i>=0;--i){
        if(depth[fa[x][i]]>=depth[y]){
            x=fa[x][i];
        }
    }
    if(x==y) return x;

    for(int i=K;i>=0;--i){
        if(fa[x][i]!=fa[y][i]){
            x=fa[x][i];
            y=fa[y][i];
        }
    }
    return fa[x][0];
}

int main()
{
    int x,y,u,v;
    ios::sync_with_stdio(0),cin.tie(0);
    cin>>n>>m;
    for(int i=1;i<n;++i){
        cin>>x>>y;
        e[x].push_back(y);
        e[y].push_back(x);
    }
    for(int i=1;i<=n;++i){
        siz[i]=e[i].size();
    }

    dfs1(1,0,0);

    for(int i=1;i<=m;++i){
        cin>>u>>v;
        if(u==v) cout<<siz[u]<<"\n";
        else{
            int lca=LCA(u,v);
            cout<<pre[u]+pre[v]-2*pre[lca]+siz[lca]<<"\n";
        }
    }
    return 0;
}
posted @ 2026-08-16 11:44  king_steph1209  阅读(8)  评论(0)    收藏  举报