算是点分治模板题。
用的一位神奔的模板,思路还是很清晰的。
不过这道题状态数(余数)只有0,1,2,所以其实树形dp就能搞,并且复杂度还低。算是点分治练手了。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<cstdlib>
using namespace std;
const int N=20005;
const int inf=0x3f3f3f3f;
int n,rt,sum,ans,mi;
int size[N];
bool vis[N];
int head[N],tot;
struct aa
{
int pre,to,dis;
}edge[N*2];
void addedge(int x,int y,int z)
{
edge[++tot].to=y;edge[tot].pre=head[x];head[x]=tot;edge[tot].dis=z;
}
void getsize(int u,int fa)
{
size[u]=1;
for (int i=head[u];i;i=edge[i].pre)
if (fa!=edge[i].to&&!vis[edge[i].to])
{
getsize(edge[i].to,u);
size[u]+=size[edge[i].to];
}
}
void getrt(int u,int fa)
{
int tmp=sum-size[u];
for (int i=head[u];i;i=edge[i].pre)
if (edge[i].to!=fa&&!vis[edge[i].to])
{
getrt(edge[i].to,u);
tmp=max(tmp,size[edge[i].to]);
}
if (tmp<mi) mi=tmp,rt=u;
}
void dfs(int u,int fa,int dis,int cnt[])
{
cnt[dis]++;
for (int i=head[u];i;i=edge[i].pre)
if (fa!=edge[i].to&&!vis[edge[i].to])
dfs(edge[i].to,u,(dis+edge[i].dis)%3,cnt);
}
void work(int u)
{
int cnt[3]={1,0,0};
for (int i=head[u];i;i=edge[i].pre)
if (!vis[edge[i].to])
{
int _cnt[3]={0,0,0};
dfs(edge[i].to,u,edge[i].dis,_cnt);
ans+=cnt[1]*_cnt[2]+cnt[2]*_cnt[1]+cnt[0]*_cnt[0];
cnt[0]+=_cnt[0];
cnt[1]+=_cnt[1];
cnt[2]+=_cnt[2];
}
}
void dfs(int u)
{
getsize(u,0);mi=inf;sum=size[u];
getrt(u,0);u=rt;
vis[u]=true;
work(u);
for (int i=head[u];i;i=edge[i].pre)
if (!vis[edge[i].to]) dfs(edge[i].to);
}
int main()
{
scanf("%d",&n);
int x,y,z;
for (int i=1;i<n;i++)
{
scanf("%d%d%d",&x,&y,&z);
addedge(x,y,z%3);
addedge(y,x,z%3);
}
dfs(1);
ans=ans*2+n;
int d=__gcd(ans,n*n);
printf("%d/%d",ans/d,n*n/d);
return 0;
}
总结
1:这里的模板是点分治的整体框架和找重心模板。
2: