BZOJ5479: tree LCA+DFS序

手完一下发现对于两个点求 LCA 来说,最优策略是对于 DFS 序相近的两个点去求.

所以把所有点按照 DFS 序排序,然后相邻两个依次求一下就行了.

code: 

#include <bits/stdc++.h>
#define ll long long  
#define N 100007 
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std;     
int n,m,edges,tim; 
int hd[N],to[N<<1],nex[N<<1],dfn[N],dep[N],son[N],size[N],top[N],fa[N];   
void add(int u,int v) 
{
    nex[++edges]=hd[u],hd[u]=edges,to[edges]=v; 
}    
void dfs(int x,int ff) 
{
    dfn[x]=++tim,dep[x]=dep[ff]+1,size[x]=1,fa[x]=ff;   
    for(int i=hd[x];i;i=nex[i]) if(to[i]!=ff) 
    {
        dfs(to[i],x);  
        size[x]+=size[to[i]];  
        if(size[to[i]]>size[son[x]]) son[x]=to[i];   
    }
}         
void dfs2(int x,int tp) 
{   
    top[x]=tp;  
    if(son[x]) dfs2(son[x],tp); 
    for(int i=hd[x];i;i=nex[i]) if(to[i]!=son[x]&&to[i]!=fa[x])  dfs2(to[i],to[i]);   
}   
int LCA(int x,int y) 
{
    while(top[x]!=top[y]) dep[top[x]]>dep[top[y]]?x=fa[top[x]]:y=fa[top[y]];   
    return dep[x]<dep[y]?x:y;   
}   
struct data 
{
    int x,col;  
    bool operator<(const data b) const { return dfn[x]<dfn[b.x]; }   
}ar[N<<1];  
void calc() 
{
    int ca,cb,cn=0,ans=0;     
    scanf("%d",&ca);  
    for(int i=1;i<=ca;++i) ++cn,scanf("%d",&ar[cn].x),ar[cn].col=1;   
    scanf("%d",&cb);  
    for(int i=1;i<=cb;++i) ++cn,scanf("%d",&ar[cn].x),ar[cn].col=2;   
    sort(ar+1,ar+1+cn);               
    for(int i=1;i<cn;++i) if(ar[i].col!=ar[i+1].col) ans=max(ans,dep[LCA(ar[i].x,ar[i+1].x)]);   
    printf("%d\n",ans);  
}      
void solve() 
{  
    int x,y; 
    scanf("%d%d",&n,&m);   
    for(int i=1;i<n;++i) scanf("%d%d",&x,&y),add(x,y),add(y,x);   
    dfs(1,0),dfs2(1,1);      
    for(int i=1;i<=m;++i) calc();  
    for(int i=1;i<=n;++i) size[i]=son[i]=top[i]=dfn[i]=hd[i]=dep[i]=fa[i]=0;   
    for(int i=1;i<=edges;++i) to[i]=nex[i]=0;  
    edges=tim=0;  
}
int main()  
{      
    // setIO("input");     
    int T; 
    scanf("%d",&T); 
    while(T--) solve(); 
    return 0; 
}

  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值