bzoj 2152: 聪聪可可【点分治】

裸的点分治,运算在模3下进行然后统计答案的时候统计余1的*余2的*2+余0的^2

#include<iostream>
#include<cstdio>
using namespace std;
const int N=20005;
int n,h[N],cnt,ans,rt,sum,si[N],hs[N],de[N],t[5];
bool v[N];
struct qwe
{
	int to,ne,va;
}e[N<<1];
int read()
{
	int r=0,f=1;
	char p=getchar();
	while(p>'9'||p<'0')
	{
		if(p=='-')
			f=-1;
		p=getchar();
	}
	while(p>='0'&&p<='9')
	{
		r=r*10+p-48;
		p=getchar();
	}
	return r*f;
}
void add(int u,int v,int w)
{
	cnt++;
	e[cnt].ne=h[u];
	e[cnt].to=v;
	e[cnt].va=w;
	h[u]=cnt;
}
int gcd(int a,int b)
{
    return b==0?a:gcd(b,a%b);
}
void getrt(int u,int fa)
{
    si[u]=1;hs[u]=0;
    for(int i=h[u];i;i=e[i].ne)
		if(!v[e[i].to]&&e[i].to!=fa)
		{
			getrt(e[i].to,u);
			si[u]+=si[e[i].to];
			hs[u]=max(hs[u],si[e[i].to]);
		}
    hs[u]=max(hs[u],sum-si[u]);
    if(hs[u]<hs[rt])
		rt=u;
}
void gtde(int u,int fa)
{
    t[de[u]]++;
    for(int i=h[u];i;i=e[i].ne)
		if(!v[e[i].to]&&e[i].to!=fa)
		{
			de[e[i].to]=(de[u]+e[i].va)%3;
			gtde(e[i].to,u);
		}
}
int clc(int u,int nw)
{
    t[0]=t[1]=t[2]=0;
    de[u]=nw;
    gtde(u,0);
    return t[1]*t[2]*2+t[0]*t[0];
}
void wk(int u)
{
    ans+=clc(u,0);
    v[u]=1;
    for(int i=h[u];i;i=e[i].ne)
		if(!v[e[i].to])
		{
			ans-=clc(e[i].to,e[i].va);
			rt=0;
			sum=si[e[i].to];
			getrt(e[i].to,0);
			wk(rt);
		}
}
int main()
{
    n=read();
    for(int i=1;i<n;i++)
    {
        int x=read(),y=read(),z=read()%3;
        add(x,y,z),add(y,x,z);
    }
    hs[0]=sum=n;
    getrt(1,0);
    wk(rt);
    int t=gcd(ans,n*n);
    printf("%d/%d",ans/t,n*n/t);
    return 0;
}
posted @ 2018-09-13 19:25  lokiii  阅读(82)  评论(0编辑  收藏  举报