树的重心 点分治

最近学了下点分治

说道点分治就得先说到树的重心

树的重心的定义是:最大的子树最小的节点。

为什么要找树的重心呢

因为找到树的重心把他变成根以后,最大的子树的大小不超过n/2,否则如果超过n/2将该子树的根作为重心将会更优。

这样可以保证递归的层数不超过logn层,同时保证每个点最多被计算logn次。

那么如何找重心呢

根据定义,我们不妨维护一下两个数组sz[]和mx[]表示以r为根的子树大小和无根树中的最大子树大小,那么mx最小的那个节点就是重心。

有两种写法 一种是

void getroot(int x,int fa)
{
    son[x]=1;f[x]=0;
    for(int i=head[x];i;i=e[i].next)
    {
        if(e[i].to==fa||vis[e[i].to])continue;
        getroot(e[i].to,x);
        son[x]+=son[e[i].to];
        f[x]=max(f[x],son[e[i].to]);
    }
    f[x]=max(f[x],sum-son[x]);
    if(f[x]<f[root])root=x;
}

另一种写法是用两个函数

void dfs_size(int x,int fa) {
    sz[x]=1;
    mx[x]=0;
    for(Edge*p=fir[x];p;p=p->next) {
        if(p->to==fa || vis[p->to]==clk) continue;
        dfs_size(p->to,x);
        sz[x] += sz[p->to];
        maxit(mx[x],sz[p->to]);
    }
}

int root=0;
void dfs_root(int r,int x,int fa) {
    maxit(mx[x],sz[r]-sz[x]);
    if(mx[x]<mx[root]) root=x;
    for(Edge*p=fir[x];p;p=p->next) {
        if(p->to==fa || vis[p->to]==clk) continue;
        dfs_root(r,p->to,x);
    }
}

我采用的后者,因为太弱了第一种一开始没看懂。

我一直觉得只用dfs一次就可以把每个子树的重心找到,

时间: 2024-11-07 20:38:35

树的重心 点分治的相关文章

POJ 1741 Tree (树的分治,树的重心)

题意:给一棵树,n个节点,给定一个数k,求任意满足dist(a,b)<=k的点对的数量. 思路: 这道题的思路比较简单,但是细节很多. 此题可以用分治法,如何分治? (1)如果path(a,b)不经过根,那么肯定在根的某棵子树下,递归解决. (2)如果path(a,b)经过根,那么肯定在根的不同子树下,处理它. 怎样处理?如果知道了每棵子树中的节点到根的距离,暂且将每棵子树的节点分到每个独立的桶里.每个节点都可以和其他桶里的点组成点对,只要距离<=k的话就满足要求了.逐个算可能超时了,用个简单

从零开始学建树(树的分治,树的重心)

分治算法在树的路径问题中的应用 一.树的分治算法 树的分治算法是分治思想在树型结构上的体现. 任一个具有n个节点的连通路,它的任何一棵树的树枝数为n-1 分治:除去树中的某些对象,使原树被分解成若干互不相交的部分. 分治算法分为两种:一种是点的分治,一种是边的分治 1.基于点的分治 1.选取一个点将无根树转为有根树 2.递归处理每一颗以根结点的儿子为根的子树 2.基于边的分治 1.在树中选取一条边 2. 将原有的树分成两棵不相交的树,递归处理. 可以证明在基于点的分治中,如果每次都选取树的重心,

树的直径、树的重心与树的点分治

树的直径 树的直径(Diameter)是指树上的最长简单路. 直径的求法:两遍搜索 (BFS or DFS) 任选一点w为起点,对树进行搜索,找出离w最远的点u. 以u为起点,再进行搜索,找出离u最远的点v.则u到v的路径长度即为树的直径. 简单证明: 如果w在直径上,那么u一定是直径的一个端点.反证:若u不是端点,则从直径另一端点到w再到u的距离比直径更长,与假设矛盾. 如果w不在直径上,且w到其距最远点u的路径与直径一定有一交点c,那么由上一个证明可知,u是直径的一个端点. 如果w到最远点u

cqyz oj | 树的分治 | 树形DP | 树的重心

Description 给定一棵N个节点的带权树,定义dist(u,v)为u,v两点间的最短路径长度,路径的长度义为路径上所有边的权和.再给定一个K,如果对于不同的两个结点a,b,如果满足dist(a,b)<=K,则称(a,b)为合法点对. 你的任务是求合法点对个数. Input 第一行包含两个个整数N和K,接下来的N-1行,每行包含三个整数:u,v,len,表示树边(u,v)的长度len. Output 一个整数,表示合法点对的数目. Sample Input 1 5 4 1 2 3 1 3

poj1655 Balancing Act 求树的重心

http://poj.org/problem?id=1655 Balancing Act Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9072   Accepted: 3765 Description Consider a tree T with N (1 <= N <= 20,000) nodes numbered 1...N. Deleting any node from the tree yields a fo

POJ 1655 Balancing Act(求树的重心)

题目大意: 就是要求树的重心,重心的定义就是删除这个点使得森林尽量平衡. 也可以让分治子树的时候使得每颗子树的数量在nlogn以内. 思路分析: son [x] 表示x的子树的数量  不包括自己. balance 表示最大的森林的节点数. 最后我们要让最大的balance 最小. balance = max (balance ,n - 1 - son[x]  , son[j] +1).. #include <cstdio> #include <iostream> #include

poj 1655 树形dp求取树的重心

http://poj.org/problem?id=1655 Description Consider a tree T with N (1 <= N <= 20,000) nodes numbered 1...N. Deleting any node from the tree yields a forest: a collection of one or more trees. Define the balance of a node to be the size of the large

poj3107 树的重心

http://poj.org/problem?id=3107 Description Last years Chicago was full of gangster fights and strange murders. The chief of the police got really tired of all these crimes, and decided to arrest the mafia leaders. Unfortunately, the structure of Chic

POJ 1655 Balancing Act (树的重心)

题意:求树的重心裸题. 拓展:树的重心可以在树分治时避免退化链时的最坏时间复杂度,提高时间效率. #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<iostream> #include<algorithm> #include<vector> #include<map> #include<queue&g