1. 程式人生 > >bzoj2152 (點分治)

bzoj2152 (點分治)

gcd void 數量 ems define geo 距離 std eof

題目鏈接:https://www.lydsy.com/JudgeOnline/problem.php?id=2152

思路:

要想兩點之間距離為3的倍數,那麽用t0表示該點距離重心的距離對3取模為0,依此得t1,t2,那麽兩點之間距離為3的倍數只有三種可能:t1-t2,t2-t1,t0-t0,將所有和重心的具體全部統計好,最後t1*t2*2+t0*t0就是

為3的倍數的點對數量

實現代碼:

#include<bits/stdc++.h>
using namespace std;
#define inf 0x7fffffff
const int M = 1e5+10;
int siz[M],f[M],head[M],vis[M],ans,cnt,t[M],sum,root,d[M];
struct node{ int to,next,w; }e[M<<1]; void init(){ ans = 0; cnt = 0; memset(vis,0,sizeof(vis)); memset(head,0,sizeof(head)); } void add(int u,int v,int w){ e[++cnt].to = v; e[cnt].w = w; e[cnt].next = head[u]; head[u] = cnt; } void get_root(int u,int fa){ siz[u]
= 1; f[u] = 0; for(int i = head[u];i;i = e[i].next){ int v = e[i].to; if(v != fa&&!vis[v]){ get_root(v,u); siz[u] += siz[v]; f[u] = max(f[u],siz[v]); } } f[u] = max(f[u],sum - siz[u]); if(f[u] < f[root]) root = u;
return ; } void get_dis(int u,int fa){ t[d[u]]++; for(int i = head[u];i;i = e[i].next){ int v = e[i].to; if(v != fa&& !vis[v]){ d[v] = (d[u] + e[i].w)%3; get_dis(v,u); } } return ; } int cal(int u,int c){ t[0] = t[1] = t[2] = 0; d[u] = c; get_dis(u,0); return t[1]*t[2]*2+t[0]*t[0]; } void solve(int v){ ans += cal(v,0); vis[v] = 1; for(int i = head[v];i;i = e[i].next){ int v = e[i].to; if(!vis[v]){ ans -= cal(v,e[i].w); sum = siz[v]; root = 0; get_root(v,0); solve(root); } } } int main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); int m,u,v,w,n; cin>>n; init(); for(int i = 1;i <= n-1;i ++){ cin>>u>>v>>w; w%=3; add(u,v,w); add(v,u,w); } f[0] = inf; sum = n; root = 0; get_root(1,0); solve(root); int x = __gcd(ans,n*n); cout<<ans/x<<"/"<<n*n/x<<endl; return 0; }

bzoj2152 (點分治)