码迷,mamicode.com
首页 > 其他好文 > 详细

点分治的一点理解

时间:2017-10-26 23:12:39      阅读:232      评论:0      收藏:0      [点我收藏+]

标签:cstring   define   sum   namespace   head   class   algorithm   ring   点分治   

今天菜狗我也学习了一波点分治。

下面是个板子

#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;
}

 

点分治的一点理解

标签:cstring   define   sum   namespace   head   class   algorithm   ring   点分治   

原文地址:http://www.cnblogs.com/lxykk/p/7739420.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!