11 条题解

  • 1
    @ 2025-1-15 10:45:04
    #include<bits/stdc++.h>
    using namespace std;
    
    const int MAXN=500000+5;
    const int MAXM=1000000+5;
    
    int head[MAXN];//链式前向星 
    
    int father[MAXN];//父亲节点 
    
    bool visited[MAXN];
    
    int bianshu;
    
    struct edge//链式前向星 
    {
    	int v,next;
    }g[2*MAXM];//双向边,记得开2倍范围 
    
    void addedge(int u,int v)//链式前向星无权值加边 
    {
    	g[++bianshu].next=head[u];
    	g[bianshu].v=v;
    	head[u]=bianshu;
    	return;
    } 
    
    queue <int> q;//bfs用
     
    int dep[MAXN];//每个点的深度 
    
    void bfs(int s,int depth)//求father 
    {
    	q.push(s);
    	dep[s]=depth;
    	while(!q.empty())
    	{
    		int ppp=q.front();
    		q.pop();
    		for(int i=head[ppp];i;i=g[i].next)//遍历 
    		{
    			if(!visited[g[i].v])
    			{
    				visited[g[i].v]=true;
    				father[g[i].v]=ppp;
    				dep[g[i].v]=dep[ppp]+1;//存储深度,比父亲节点深度大1 
    				q.push(g[i].v);
    			}
    		}
    	}
    }
    
    int jump[MAXN][35];//定义:j[a][b]为a号点往根节点方向走(1<<b)次后的节点编号 
    
    int main()
    {
    	int n,q,s;
    	int uu,vv;
    	int a,b;
    	int tmp;//深度差 
    	
    	scanf("%d%d",&n,&q);//有时候需要读入s 
    	s=1; 
    	
    	for(int i=1;i<=n-1;++i)
    	{
    		scanf("%d%d",&uu,&vv);
    		addedge(uu,vv);
    		addedge(vv,uu);
    	}//加边 
    	
    	father[s]=0;//注意:father[根]一定要设为0,否则后面跳跃时出问题 
    	visited[s]=true;
    	bfs(s,1);//求father数组 
    	
    	for(int i=1;i<=n;++i)
    	{
    		jump[i][0]=father[i];
    	}//jump初值 
    	for(int j=1;j<=30;++j)
    	{
    		for(int i=1;i<=n;++i)
    		{
    			jump[i][j]=jump[jump[i][j-1]][j-1];
    		}
    	}//初始化jump数组 
    	 
    	while(q--)//操作 
    	{
    		scanf("%d%d",&a,&b);
    		
    		tmp=(dep[a]>dep[b]?dep[a]-dep[b]:dep[b]-dep[a]);//深度差值 
    		
    		if(dep[a]>dep[b]) //每次判断是否跳跃(1<<k)次,跳跃到同一深度 
    		{
    			for(int k=30;k>=0;--k)
    			{
    				if(tmp>=(1<<k))
    				{
    					a=jump[a][k];
    					tmp-=(1<<k);
    				}
    			} 
    		}
    		else if(dep[b]>dep[a]) 
    		{
    			for(int k=30;k>=0;--k)
    			{
    				if(tmp>=(1<<k))
    				{
    					b=jump[b][k];
    					tmp-=(1<<k);
    				}
    			} 
    		}//使得a,b位于同一深度 
    		
    		if(a==b)//跳到同一个点,即LCA就是当前的点,需要特判。 
    		{
    			printf("%d\n",a);
    			continue;
    		}
    		for(int k=30;k>=0;--k)
    		{
    			if((jump[a][k]^jump[b][k]))//异或符号^在此处等价于!= 符号 
    			{
    				a=jump[a][k];
    				b=jump[b][k];
    			}
    		}//跳2的k次方次
    		 
    		printf("%d\n",father[a]);
    	}
    	return 0;
    }
    
    

    信息

    ID
    121
    时间
    2000ms
    内存
    256MiB
    难度
    6
    标签
    递交数
    692
    已通过
    202
    上传者