1 해설

  • 0
    @ 2025-8-24 22:56:35

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Furina
    芙宁娜太可爱啦!| 青雀太可爱啦! | 题单 592617

    搬运于2025-08-24 22:56:35,当前版本为作者最后更新于2024-04-04 18:35:17,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    题意简述:

    无。

    题解:

    此处阅读体验更佳?

    看完题目之后,我们首先要考虑一个问题:什么时候要用到传送门?

    对于树上的两个点 xxyy,如果不考虑传送门的话,最短距离就是这两个点到它们的最近公共祖先的距离和。

    那么如果用传送门更优,那么肯定满足这一个条件:xx 到它最近的传送门距离加上 yy 到它最近的传送门距离小于 xxyy 到它们的最近公共祖先的距离和。

    大家可以自己验证一些普通和特殊情况,此处就不给出证明了。

    那么我们就可以先求出每个点到最近的传送门距离 opiop_i,对于询问,再输出 $\min(op_x+op_y,dep_x-dep_{lca(x,y)}+dep_y-dep_{lca(x,y)})$。

    那么就可以写代码了。

    注意:

    • 可能没有传送门(代码中注释 A)。

    代码如下:

    #include<bits/stdc++.h>
    #define N 200100
    #define I_love_Furina return//发电+放抄袭(?)
    #define forever 0
    #define foreverr 1 
    #define int long long
    using namespace std;
    int n,T,m,q,head[N],op[N],num,f[N][20],dep[N];
    struct node{int to,nxt;}a[N*2];
    inline void add(int u,int v){a[++num].to=v,a[num].nxt=head[u],head[u]=num;}
    inline void solve(){//求最近传送阵距离
    	queue<int> q;
    	for(int i=1,x;i<=m;i++)cin>>x,q.push(x),op[x]=0;//把所有的传送阵位置压入队列,跑bfs
    	while(!q.empty()){
    		int u=q.front();
    		q.pop();
    		for(int i=head[u];i;i=a[i].nxt){
    			int v=a[i].to;
    			if(op[v]!=-1)continue;//避免重复遍历
    			op[v]=op[u]+1,q.push(v);
    		}
    	}
    	I_love_Furina ;
    }
    void dfs(int x,int fa){
    	f[x][0]=fa,dep[x]=dep[fa]+1;
    	for(int i=1;i<=19&&f[f[x][i-1]][i-1];i++)f[x][i]=f[f[x][i-1]][i-1];//计算祖宗
    	for(int i=head[x];i;i=a[i].nxt)if(a[i].to!=fa)dfs(a[i].to,x);
    	I_love_Furina ;
    } 
    inline int lca(int x,int y){//求最近公共祖先
    	if(dep[x]<dep[y])swap(x,y);
    	for(int i=19;i>=0;i--)if(dep[f[x][i]]>=dep[y])x=f[x][i];
    	if(x==y)I_love_Furina x;
    	for(int i=19;i>=0;i--)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
    	I_love_Furina f[x][0];//注意,是返回x的父亲
    }
    signed main(){
    	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    	cin>>n>>m>>q;
    	for(int i=1,u,v;i<n;i++)cin>>u>>v,add(u,v),add(v,u),op[i]=op[i+1]=-1;
    	dfs(1,0),solve();//跑lca和最近传送阵距离
    	while(q--){
    		int x,y;
    		cin>>x>>y;
    		int LCA=lca(x,y);
    		//cout<<lca(x,y)<<" "<<op[x]<<" "<<op[y]<<endl;
    		cout<<min(dep[x]-dep[LCA]+dep[y]-dep[LCA],(op[x]==-1||op[y]==-1?3156781267:op[x]+op[y]))<<endl;//A:防止输出-2
    	}
    	I_love_Furina forever;
    }
    
    

    完结撒花咯(点个赞再走)。

    • 1

    정보

    ID
    9992
    시간
    1000ms
    메모리
    512MiB
    난이도
    4
    태그
    제출 기록
    0
    맞았습니다.
    0
    아이디