最近学了下点分治

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

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

为什么要找树的重心呢

因为找到树的重心把他变成根以后,最大的子树的大小不超过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一次就可以把每个子树的重心找到,后来发现每一棵子树都要找一次orz感觉复杂度一下就上去了

 

然后有两道找树的重心的题

poj1655

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<algorithm>
 5 #include<cstring>
 6 
 7 using namespace std;
 8 
 9 const int Maxn=20000+10,INF=0x7fffffff;
10 
11 struct Edge{
12     int to;
13     Edge*next;
14     Edge(int to=0,Edge* next=0):to(to),next(next){}
15 }pool[Maxn*2],*fir[Maxn],*pis=pool;
16 
17 void AddEdge(int from,int to){
18     *pis=Edge(to,fir[from]);fir[from]=pis++;
19     *pis=Edge(from,fir[to]);fir[to]=pis++;
20 }
21 
22 int sz[Maxn],mx[Maxn];
23 void dfs_size(int x,int fa) {
24     sz[x]=1;
25     mx[x]=0;
26     for(Edge*p=fir[x];p;p=p->next) {
27         if(p->to==fa) continue;
28         dfs_size(p->to,x);
29         sz[x] += sz[p->to];
30         mx[x]=max(mx[x],sz[p->to]);
31     }
32 }
33 
34 int root;
35 
36 void dfs_root(int r,int x,int fa) {
37     mx[x]=max(mx[x],sz[r]-sz[x]);
38     if(mx[root]>mx[x]) root=x;
39     for(Edge*p=fir[x];p;p=p->next) {
40         if(p->to==fa) continue;
41         dfs_root(r,p->to,x);
42     }
43 }
44 
45 int n;
46 void init() {
47     root=0;
48     mx[0]=INF;
49     pis=pool;
50     memset(fir,0,sizeof fir);
51     for(int i=1;i<n;i++) {
52         int u,v;
53         scanf("%d%d",&u,&v);
54         AddEdge(u,v);
55     }
56 }
57 
58 int main() {
59 #ifdef DEBUG
60     freopen("in.txt","r",stdin);
61     freopen("out.txt","w",stdout);
62 #endif
63     
64     int T;
65     for(scanf("%d",&T);T--;) {
66         scanf("%d",&n);
67         init();
68         dfs_size(1,0);
69         dfs_root(1,1,0);
70         printf("%d %d\n",root,mx[root]);
71     }
72     
73     return 0;
74 }
View Code

相关文章: