bzoj2152点分治

来源:互联网 发布:android studio 源码 编辑:程序博客网 时间:2024/06/06 18:08

考虑三的倍数的计算:
t[1]t[2]+t[0]2(每一个点对都计算两次),然后用整个点减去只在子树中出现的即可

#include<iostream>#include<cstdio>#include<cmath>#include<cstring>#include<algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fod(i,a,b) for(int i=a;i>=b;i--)using namespace std;int read(){    int x=0,f=1;char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}const int N=1e5+10,inf=(1<<30);int last[N],t[10],dis[N],s[N],vis[N],f[N],n,K,len,root,sum,ans;struct Edge{int to,next,val;Edge(int to=0,int next=0,int val=0):to(to),next(next),val(val){}}e[N<<1];void add_edge(int u,int v,int w){e[++len]=Edge(v,last[u],w);last[u]=len;}void getroot(int x,int fa){    s[x]=1;f[x]=0;    for(int i=last[x];i;i=e[i].next) {        int id=e[i].to;        if(id==fa||vis[id])continue;        getroot(id,x);        s[x]+=s[id];f[x]=max(f[x],s[id]);    }                                                                                   f[x]=max(f[x],sum-s[x]);    if(f[x]<f[root])root=x;}void getdep(int x,int fa){    t[dis[x]]++;    for(int i=last[x];i;i=e[i].next) {        int id=e[i].to;        if(id==fa||vis[id])continue;        dis[id]=(dis[x]+e[i].val)%3;        getdep(id,x);    }}int cal(int x,int w){    t[0]=t[1]=t[2]=0;dis[x]=w;    getdep(x,0);    return t[0]*t[0]+t[1]*t[2]*2;}void solve(int x){    ans+=cal(x,0);vis[x]=1;    for(int i=last[x];i;i=e[i].next) {        int id=e[i].to;        if(vis[id])continue;        ans-=cal(id,e[i].val);        sum=s[id];root=0;getroot(id,0);        solve(root);    }}int gcd(int a,int b){return b==0?a:gcd(b,a%b);}int main(){    n=read();    for(int u,v,w,i=1;i<n;i++) {        u=read();v=read();w=read()%3;        add_edge(u,v,w);add_edge(v,u,w);    }    sum=n;    f[0]=inf;getroot(1,0);    solve(root);    int t=gcd(ans,n*n);    printf("%d/%d\n",ans/t,n*n/t);    return 0;} 
原创粉丝点击