bzoj 2152: 聪聪可可
点分治时维护出t[0],t[1],t[2],分别表示路径长度%3之后的数量。
答案就是t[0]^2+2*t[1]*t[2]
(能不能依次处理子树呢?????感觉这个题可以。。。。)
1 #include<bits/stdc++.h> 2 #define N 100005 3 #define M 10000005 4 #define LL long long 5 #define inf 0x3f3f3f3f 6 using namespace std; 7 inline int ra() 8 { 9 int x=0,f=1; char ch=getchar(); 10 while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();} 11 while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();} 12 return x*f; 13 } 14 int n,K,cnt,sum,ans,root; 15 int head[20005],deep[20005],d[20005],f[20005],size[20005],t[5]; 16 bool vis[20005]; 17 struct data{int to,next,v;}e[40005]; 18 void insert(int x, int y, int v){e[++cnt].next=head[x]; e[cnt].to=y; e[cnt].v=v; head[x]=cnt;} 19 void getroot(int x, int fa) 20 { 21 size[x]=1; f[x]=0; 22 for (int i=head[x];i;i=e[i].next) 23 { 24 if (e[i].to==fa || vis[e[i].to]) continue; 25 getroot(e[i].to,x); 26 size[x]+=size[e[i].to]; 27 f[x]=max(f[x],size[e[i].to]); 28 } 29 f[x]=max(f[x],sum-size[x]); 30 if (f[x]<f[root]) root=x; 31 } 32 void getdeep(int x, int fa) 33 { 34 t[d[x]]++; 35 for (int i=head[x];i;i=e[i].next) 36 { 37 if (vis[e[i].to] || e[i].to==fa) continue; 38 d[e[i].to]=(d[x]+e[i].v)%3; 39 getdeep(e[i].to,x); 40 } 41 } 42 int cal(int x, int tot) 43 { 44 d[x]=tot; 45 memset(t,0,sizeof(t)); 46 getdeep(x,0); 47 return t[0]*t[0]+t[1]*t[2]*2; 48 } 49 void solve(int x) 50 { 51 ans+=cal(x,0); vis[x]=1; 52 for (int i=head[x];i;i=e[i].next) 53 { 54 if (vis[e[i].to]) continue; 55 ans-=cal(e[i].to,e[i].v); 56 sum=size[e[i].to]; root=0; 57 getroot(e[i].to,0); 58 solve(root); 59 } 60 } 61 int main() 62 { 63 n=ra(); 64 for (int i=1; i<n; i++) 65 { 66 int x=ra(),y=ra(),v=ra()%3; 67 insert(x,y,v); insert(y,x,v); 68 } 69 sum=n; f[0]=inf; 70 getroot(1,0); 71 solve(root); 72 int t=__gcd(ans,n*n); 73 printf("%d/%d\n",ans/t,n*n/t); 74 return 0; 75 }