最近学了下点分治
说道点分治就得先说到树的重心
树的重心的定义是:最大的子树最小的节点。
为什么要找树的重心呢
因为找到树的重心把他变成根以后,最大的子树的大小不超过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 }