BZOJ2152: 聪聪可可

【传送门:BZOJ2152


简要题意:

  给出一棵n个点的树,和每条边的边权,求出有多少个点对,它们的距离为3的倍数

  最后输出求出的点对数/总点对数的最简分数


题解:

  点分治例题

  求值时设t[i]为路径的值%3==i的情况数,那么答案就为t[1]*t[2]*2+t[0]*t[0]


参考代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
struct node
{
    int x,y,d,next;
}a[81000];int len,last[41000];
void ins(int x,int y,int d)
{
    len++;
    a[len].x=x;a[len].y=y;a[len].d=d;
    a[len].next=last[x];last[x]=len;
}
int tot[41000],root,sum,ms[41000];
bool v[41000];
void getroot(int x,int fa)
{
    tot[x]=1;ms[x]=0;
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(y!=fa&&v[y]==false)
        {
            getroot(y,x);
            tot[x]+=tot[y];
            ms[x]=max(ms[x],tot[y]);
        }
    }
    ms[x]=max(ms[x],sum-tot[x]);
    if(ms[root]>ms[x]) root=x;
}
int t[3];
void ask(int x,int fa,int d)
{
    t[d%3]++;
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(y!=fa&&v[y]==false)
        {
            ask(y,x,(d+a[k].d)%3);
        }
    }
}    
int ans=0;
int k;
int cal(int x,int d)
{
    t[0]=t[1]=t[2]=0;
    ask(x,0,d);
    return 2*t[1]*t[2]+t[0]*t[0];
}
void solve(int x)
{
    ans+=cal(x,0);
    v[x]=true;
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(v[y]==false)
        {
            ans-=cal(y,a[k].d);
            sum=tot[y];
            ms[0]=1<<31-1;
            root=0;getroot(y,x);
            solve(root);
        }
    }
}
int gcd(int a,int b)
{
    if(a==0) return b;
    else return gcd(b%a,a);
}
int main()
{
    int n;
    scanf("%d",&n);
    len=0;memset(last,0,sizeof(last));
    for(int i=1;i<n;i++)
    {
        int x,y,d;
        scanf("%d%d%d",&x,&y,&d);
        ins(x,y,d);ins(y,x,d);
    }
    memset(v,false,sizeof(v));
    ans=0;
    sum=n;
    ms[0]=1<<31-1;
    root=0;getroot(1,0);
    solve(root);
    int all=n*n;
    int GCD=gcd(ans,all);
    printf("%d/%d\n",ans/GCD,all/GCD);
    return 0;
}

 

posted @ 2018-04-27 11:23  Star_Feel  阅读(163)  评论(0编辑  收藏  举报