zoukankan      html  css  js  c++  java
  • 关于树

    树的直径

    树的直径是指树中两个点之间的最大距离,即最长的一条链。

    容易证明(信奥不需要证明),树的直径的起始点是该树的叶子节点。

    求树的直径一般有两种方法,一种是两遍(dfs),另一种是树形(DP)

    两遍dfs

    我们随便从一个点(u)出发,然后去寻找一个离这个点最远的一个点(v)

    然后再从这个点v出发去寻找最长链。

    void dfs(int x,int p) {
    	for(re int i = head[x] ; i ; i = t[i].next) {
    		int v = t[i].to;
    		if(vis[v]) continue;
    		vis[v]=1;
    		dis[v] = p + t[i].dis;
    		if(dis[v] > ans) {
    			ans=dis[v];
    			node=v;
    		}
    		dfs(v,dis[v]);
    	}
    }
    

    树形DP

    (f[x][1])维护在x的子树中的最长链。

    (f[x][2])维护在x的子树中的次长链。

    那么在(x)的子树中的最长链就是(f[x][1]+f[x][2]).

    void dfs(int x, int fa) {
    	for(re int i = head[x]; i; i = t[i].net) {
    		int v = t[i].to;
    		if(v == fa) continue; dfs(v,x);
    		if(l[v][1] + t[i].dis > l[x][1])
    			l[x][2] = l[x][1], l[x][1] = l[v][1] + t[i].dis;
    		else if(l[v][1] + t[i].dis > l[x][2])
    			l[x][2] = l[v][1] + t[i].dis;
    		if(lian < l[x][1]+l[x][2]) lian = l[x][1] + l[x][2];
    	}
    }
    

    树上求LCA

    LCA(Lowest Common Ancestors)即最近公共祖先,

    是指在有根树中,找出某两个结点(u)(v)最近的公共祖先.

    目前只会两种方法,倍增和树链剖分。

    倍增求LCA

    f[x][i]是指节点x向上第(2^i)个节点。

    有一个关键的式子:(f[x][i]=f[f[x][i-1]][i-1].)

    void dfs(int x, int fa) {
    	f[x][0] = fa; deep[x] = deep[fa] + 1;
    	for(re int i = 1; (1 << i) <= deep[x]; ++ i) //不超过根节点
    		f[x][i] = f[f[x][i-1]][i-1];
    	for(re int i = head[x]; i; i = t[i].net)
    		if(t[i].to != fa) dfs(t[i].to, x);
    }
    int lca(int x, int y) {
    	if(deep[x] < deep[y]) std :: swap(x,y); // 让x为深度更大的
    	for(re int i = 21; i >= 0; -- i)
    		if(deep[x] - (1 << i) >= deep[y]) // 使x的深度始终大于或等于y
    			x = f[x][i];
    	if(x == y) return x;
    	for(re int i = 21; i >= 0; -- i)
    		if(f[x][i] == f[y][i]) continue;
    		else x = f[x][i], y = f[y][i];
    	return f[x][0]; // x的父亲一定是LCA
    }
    

    树链剖分求LCA

    每一个节点都去维护一个子树大小,深度,链顶,父亲,最重链(最大子树)。

    第一次(dfs)去求深度,父亲和子树大小。

    第二次(dfs)去求链顶。

    (LCA)的时候,不断的更新链顶深度大的,使其在同一深度。

    (LCA)就是深度小的那个。

    void dfs_1(int x) {
    	deep[x] = deep[fa[x]] + 1; size[x] = 1;
    	for(re int i = head[x]; i; i = t[i].net) {
    		int v = t[i].to;
    		if(fa[x] == v) continue; // 父亲已经遍历了
    		fa[v] = x; dfs_1(v);
    		size[x] += size[v];
    		if(size[son[x]] < size[v] || !son[x]) son[x] = v;
    		//没有儿子或者是儿子的子树重量没有当前子树重量大,都会更新
    	}
    }
    void dfs_2(int x, int tp) {
    	top[x] = tp; // 一条链上的人链顶都相同
    	if(son[x]) dfs_2(son[x],tp); // 还有儿子
    	for(re int i = head[x]; i; i = t[i].net) {
    		int v = t[i].to;
    		if(fa[x] == v || son[x] == v) continue;
    	    // 父亲和儿子都遍历过了
    		dfs_2(v, v);
    	}
    }
    int lca(int x, int y) {
    	while(top[x] != top[y]) { // 更新深度大的
    		if(deep[top[x]] < deep[top[y]]) y = fa[top[y]];
    		else x = fa[top[x]];
    	}
    	return deep[x] < deep[y] ? x : y;
    }
    
  • 相关阅读:
    eclipse adt 项目依赖,使用git上的项目
    Fragment用app包还是v4包解析
    nohttp的使用
    安卓学习笔记2
    HashMap和HashSet的区别
    Fragment 和 FragmentActivity的使用
    Android Studio 使用教程
    打开eclipse报错:发现了以元素 'd:skin' 开头的无效内容。此处不应含有子元素。
    java 四种内部类和内部接口
    安卓学习笔记1
  • 原文地址:https://www.cnblogs.com/ypay/p/11637343.html
Copyright © 2011-2022 走看看