题意:给你一颗树,询问路径和是3的倍数的路径有多少条
思路:日常搬运点分治,这个题其实是运用了取模,三的倍数其实可以转化为对3取模,然后直接点分治
代码:(一直T,最后发现是getroot时写错了)
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; int read() { int x=0,w=1;char ch=getchar(); while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar(); if (ch=='-') w=0,ch=getchar(); while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return w?x:-x; } const int maxn=20005; struct edge { int to,next,w; }a[maxn<<1]; int n,m,k,head[maxn],cnt; int root,sum,vis[maxn],sz[maxn]; int f[maxn],dep[maxn]; int ans; int t[5]; int MAX(int x,int y) { return x>y?x:y; } int gcd(int x,int y) { return y==0?x:gcd(y,x%y); } void addedge(int u,int v,int w) { a[++cnt].to=v; a[cnt].next=head[u]; a[cnt].w=w; head[u]=cnt; } void getroot(int u,int fa) { sz[u]=1;f[u]=0; for(int e=head[u];e;e=a[e].next){ int v=a[e].to;if(v==fa||vis[v])continue; getroot(v,u); sz[u]+=sz[v]; f[u]=MAX(f[u],sz[v]); } f[u]=MAX(f[u],sum-sz[u]); if(f[u]<f[root])root=u; } void getdeep(int u,int fa) { t[dep[u]%3]++; for(int e=head[u];e;e=a[e].next){ int v=a[e].to;if(v==fa||vis[v])continue; dep[v]=dep[u]+a[e].w; getdeep(v,u); } } int calc(int u,int d0) { dep[u]=d0;t[0]=t[1]=t[2]=0; getdeep(u,0); return t[0]*t[0]+2*t[1]*t[2]; } void solve(int u) { ans+=calc(u,0);vis[u]=1; for(int e=head[u];e;e=a[e].next){ int v=a[e].to;if(vis[v])continue; ans-=calc(v,a[e].w); sum=sz[v];root=0; getroot(v,0); solve(root); } } int main() { n=read(); for(int i=1;i<n;++i){ int u=read(),v=read(),w=read(); addedge(u,v,w); addedge(v,u,w); } f[0]=sum=n; getroot(1,0); solve(root); int as=gcd(ans,n*n); ans/=as; printf("%d/%d ",ans,n*n/as); return 0; }