• LCA回顾(主要针对倍增算法)


    这个有两种方法:

    一、倍增

    就是维护一个节点的第(2^0, 2^1, 2^2 ...)层父亲,这样的话我们在后面查询的时候就可以直接“跳”着找。

    void pushup()
    {
    	step=log(maxd*1.0)/log(2.0);
    
    	for(int i=1;i<=step;i++)
    		for(int p=1;p<=n;p++) if( fa[p][i-1] ) fa[p][i]=fa[ fa[p][i-1] ][i-1];
    
    	return;
    }
    

    然后查询的时候,先让两个点跳到同一深度

    所以要让较深的一个点先往上跳:

    if( dep[x]<dep[y] ) swap(x,y);
    for(int i=step;i>=0;i--) if( dep[x]-(1<<i)>=dep[y] ) x=fa[x][i];
    

    第二行相当于将(dep(x)-dep(y))的值做二进制拆分


    跳到同一深度之后,如果两个节点已经跳到同一个位置,就直接退出。

    否则,就要继续同时往上跳,但是,在跳的时候要保证:它们各自跳到的位置必须是不一样的!不然的话它们可能都跳到了(LCA)的上面!

    整个功能段见下(省略了建图部分):

    struct LCA
    {
    	int fa[maxn][22],dep[maxn];
    	int maxd;
    	
    	void dfs(int x,int f,int d)
    	{
    		fa[x][0]=f,dep[x]=d;
    		maxd=max( maxd,d );
    		
    		for(int i=G.Head[x];i;i=G.Next[i])
    		{
    			Graph::Edge e=G.edges[i];
    			if( e.to==f ) continue;
    			
    			dfs(e.to,x,d+1);
    		}
    		
    		return;
    	}
    	
    	int step;
    	
    	void pushup()
    	{
    		step=log(maxd*1.0)/log(2.0);
    		
    		for(int i=1;i<=step;i++)
    			for(int p=1;p<=n;p++) if( fa[p][i-1] ) fa[p][i]=fa[ fa[p][i-1] ][i-1];
    		
    		return;
    	}
    	
    	int LCA(int x,int y)
    	{
    		if( dep[x]<dep[y] ) swap(x,y);
    		
    		for(int i=step;i>=0;i--) if( dep[x]-(1<<i)>=dep[y] ) x=fa[x][i];
    		if( x==y ) return y;
    		
    		for(int i=step;i>=0;i--)
    			if( fa[x][i]!=fa[y][i] ) x=fa[x][i],y=fa[y][i];
    		
    		return fa[x][0];
    	}
    }SOL;
    

    二、树链剖分

    这个更简单,用(top)数组直接跳就行了……

  • 相关阅读:
    2016年第9本:系统之美
    2016年第8本:不可思议的心理控制实验
    2016年第7本:非暴力沟通
    用SDWebImage渐变加载图片
    iOS相册、相机、通讯录权限获取
    屏蔽iOS10模拟器海量的垃圾debug信息
    Swift
    Swift
    PlaceholderImageView
    Swift
  • 原文地址:https://www.cnblogs.com/info---tion/p/11282987.html
Copyright © 2020-2023  润新知