点分治求路径长度为3的倍数的链的条数,结果用分数表示。
这道题明显是树形dp简单,然而还是写了点分治(练习所用没办法啊)。
AC代码如下:
#include<iostream> #include<cstdio> #include<cstring> #define N 50005 using namespace std; int n,m,tot,sum,rt,ans,t[3],fst[N],pnt[N],len[N],nxt[N],d[N],sz[N],f[N]; bool vis[N]; int read(){ int x=0; char ch=getchar(); while (ch<'0' || ch>'9') ch=getchar(); while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); } return x; } void add(int aa,int bb,int cc){ pnt[++tot]=bb; nxt[tot]=fst[aa]; len[tot]=cc; fst[aa]=tot; } void dfs(int x,int fa){ sz[x]=f[x]=1; int p; for (p=fst[x]; p; p=nxt[p]){ int v=pnt[p]; if (v==fa || vis[v]) continue; dfs(v,x); sz[x]+=sz[v]; f[x]=max(f[x],sz[v]); } f[x]=max(f[x],sum-sz[x]); if (f[x]<f[rt]) rt=x; } void getdep(int x,int fa){ t[d[x]]++; int p; for (p=fst[x]; p; p=nxt[p]){ int v=pnt[p]; if (v==fa || vis[v]) continue; d[v]=(d[x]+len[p])%3; getdep(v,x); } } int work(int x,int num){ d[x]=num; memset(t,0,sizeof(t)); getdep(x,0); return t[0]*t[0]+t[1]*t[2]*2; } void solve(int x){ ans+=work(x,0); vis[x]=1; int p; for (p=fst[x]; p; p=nxt[p]){ int v=pnt[p]; if (vis[v]) continue; ans-=work(v,len[p]); sum=sz[v]; rt=0; dfs(v,x); solve(rt); } } int gcd(int x,int y){ return (y)?gcd(y,x%y):x; } void print_ans(int x,int y){ int tmp=gcd(x,y); printf("%d/%d\n",x/tmp,y/tmp); } int main(){ n=read(); int i; for (i=1; i<n; i++){ int x=read(),y=read(),z=read()%3; add(x,y,z); add(y,x,z); } f[rt=0]=sum=n; dfs(1,0); solve(rt); print_ans(ans,n*n); return 0; }
2015.11.15
by lych