聪聪可可(点分治)

来源:互联网 发布:言而当知也 编辑:程序博客网 时间:2024/05/18 01:49
#include<iostream>#include<cstdio>#include<cstdlib>#include<algorithm>#define maxn 40000using namespace std;struct eg{    int to,v,nxt;}b[maxn];int head[maxn],tot=0,f[maxn],sz[maxn],vis[maxn],d[maxn]={0},ans,root,sum,t1[5];int gcd(int x,int y){return y?gcd(y,x%y):x;}void link(int x,int y,int z){    b[++tot].nxt=head[x];    b[tot].to=y;    b[tot].v=z;    head[x]=tot;}void getroot(int u,int fa){    sz[u]=1,f[u]=0;    for (int i=head[u];i;i=b[i].nxt)    {        int t=b[i].to;        if (vis[t]||t==fa) continue;        getroot(t,u);        sz[u]+=sz[t];        f[u]=max(f[u],sz[t]);    }    f[u]=max(f[u],sum-sz[u]);    if (f[root]>f[u]) root=u;}void getdeep(int x,int fa){    t1[d[x]]++;    for (int i=head[x];i;i=b[i].nxt)    {        int t=b[i].to;        if (vis[t]||t==fa) continue;        d[t]=(d[x]+b[i].v)%3;        getdeep(t,x);    }}int cal(int x,int vv){    d[x]=vv%3;    t1[0]=t1[1]=t1[2]=0;    getdeep(x,0);    return t1[1]*t1[2]*2+t1[0]*t1[0];}void work(int x){    ans+=cal(x,0);    vis[x]=1;    for (int i=head[x];i;i=b[i].nxt)    {        int t=b[i].to;        if (vis[t]) continue;        ans-=cal(t,b[i].v);        sum=sz[t];        root=0;        getroot(t,0);        work(root);    }}int main(){    int n;    scanf ("%d",&n);    for (int i=1;i<n;++i)    {        int x,y,w;        scanf ("%d%d%d",&x,&y,&w);        link(x,y,w);        link(y,x,w);    }    root=0;f[0]=n,sum=n;    getroot(1,0);    work(root);    int l=gcd(ans,n*n);    cout<<(ans/l)<<"/"<<(n*n/l);    return 0;}

点分治板子
然而想那个 t1[1]*t1[2]*2+t1[0]*t1[0]想了好久
就是最基本的组合方法 毕竟(2,5)和(5,2)可是要算两次的
画画图就好了
(不要像我一样盯着大佬们的显然可得懵逼23333)

1 0
原创粉丝点击