点分治的一点理解
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了点分治的一点理解相关的知识,希望对你有一定的参考价值。
今天菜狗我也学习了一波点分治。
下面是个板子
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define N 20010 using namespace std; int n,u,v,w,ans,sum,cnt,head[N],f[N],root,sz[N],t[5],d[N]; bool vis[N]; struct node{ int next,to,dis; }e[N*20]; void add(int u,int v,int w) { e[++cnt].next=head[u],e[cnt].to=v,e[cnt].dis=w,head[u]=cnt; } void getdeep(int u,int fa) { t[d[u]]++; for(int i=head[u];i;i=e[i].next) { int v=e[i].to; if(v==fa||vis[v])continue; d[v]=(d[u]+e[i].dis)%3; getdeep(v,u); } } int cal(int u,int v) { t[0]=t[1]=t[2]=0; d[u]=v; getdeep(u,0); return t[1]*t[2]*2+t[0]*t[0]; } void getroot(int u,int fa) { sz[u]=1,f[u]=0;//f数组记录以u为根的最大子树的大小,将最大子树的顶点数最小的点当作分割顶点 for(int i=head[u];i;i=e[i].next) { int v=e[i].to; if(v==fa||vis[v])continue;//如果vis访问过,表示这个点已经被删掉了 getroot(v,u); sz[u]+=sz[v]; f[u]=max(f[u],sz[v]); } f[u]=max(f[u],sum-sz[u]);//以当前树为时还要考虑其父亲的子数大小 if(f[u]<f[root])root=u;//更新重心 } void solve(int u) { ans+=cal(u,0); vis[u]=1;//将当前点标记 for(int i=head[u];i;i=e[i].next) { int v=e[i].to; if(vis[v])continue; ans-=cal(v,e[i].dis); root=0;//初始化根 getroot(v,0);//找到联通块的重心 solve(root);//递归下一联通块 } } int gcd(int a,int b) { return !b?a:gcd(b,a%b); } int main() { scanf("%d",&n); for(int i=1;i<=n-1;i++)scanf("%d%d%d",&u,&v,&w),w%=3,add(u,v,w),add(v,u,w); sum=f[0]=n; getroot(1,0);//找树的重心 solve(root);//点分治 int t=gcd(ans,n*n); printf("%d/%d\n",ans/t,n*n/t); return 0; }
以上是关于点分治的一点理解的主要内容,如果未能解决你的问题,请参考以下文章