聰聰可可[點分治]
阿新 • • 發佈:2018-11-04
題目描述
聰聰和可可是兄弟倆,他們倆經常為了一些瑣事打起來,例如家中只剩下最後一根冰棍而兩人都想吃、兩個人都想玩兒電腦(可是他們家只有一臺電腦)……遇到這種問題,一般情況下石頭剪刀布就好了,可是他們已經玩兒膩了這種低智商的遊戲。
他們的爸爸快被他們的爭吵煩死了,所以他發明了一個新遊戲:由爸爸在紙上畫n個“點”,並用n-1條“邊”把這n個“點”恰好連通(其實這就是一棵樹)。並且每條“邊”上都有一個數。接下來由聰聰和可可分別隨即選一個點(當然他們選點時是看不到這棵樹的),如果兩個點之間所有邊上數的和加起來恰好是3的倍數,則判聰聰贏,否則可可贏。
聰聰非常愛思考問題,在每次遊戲後都會仔細研究這棵樹,希望知道對於這張圖自己的獲勝概率是多少。現請你幫忙求出這個值以驗證聰聰的答案是否正確。
輸入格式:
輸入的第1行包含1個正整數n。後面n-1行,每行3個整數x、y、w,表示x號點和y號點之間有一條邊,上面的數是w。
輸出格式:
以即約分數形式輸出這個概率(即“a/b”的形式,其中a和b必須互質。如果概率為1,輸出“1/1”)。
輸入樣例#1:
5 1 2 1 1 3 2 1 4 1 2 5 3
輸出樣例#1:
13/25
說明
【樣例說明】
13組點對分別是(1,1) (2,2) (2,3) (2,5) (3,2) (3,3) (3,4) (3,5) (4,3) (4,4) (5,2) (5,3) (5,5)。
【資料規模】
對於100%的資料,n<=20000。
先找樹的重心,求經過他的路徑倍數為3的條數
然後遞迴找兒子,再在兒子的子樹中找重心
如何求條數?我們維護cnt[0],cnt[1],cnt[2] 表示到根路徑長度%3的點的個數
答案就是 cnt[1]*cnt[2]*2 + cnt[0]*cnt[0]
#include<bits/stdc++.h> #define N 40005 using namespace std; int first[N],next[N],to[N],w[N],tot; int n,rt,cnt[5],dis[N],size[N],Maxson[N]; int ans,siz,vis[N]; int read(){ int cnt=0;char ch=0; while(!isdigit(ch))ch=getchar(); while(isdigit(ch))cnt=cnt*10+(ch-'0'),ch=getchar(); return cnt; } int gcd(int a,int b){return !b?a:gcd(b,a%b);} void add(int x,int y,int z){ next[++tot]=first[x],first[x]=tot,to[tot]=y,w[tot]=z; } void get_root(int u,int f){ size[u]=1,Maxson[u]=0; for(int i=first[u];i;i=next[i]){ int t=to[i]; if(t==f||vis[t]) continue; get_root(t,u); size[u] += size[t]; Maxson[u] = max(Maxson[u] , size[t]); } Maxson[u] = max(Maxson[u] , siz-Maxson[u]); if(Maxson[rt] > Maxson[u]) rt = u; } void get_dis(int u,int f){ cnt[dis[u]%3]++; for(int i=first[u];i;i=next[i]){ int t=to[i]; if(t==f||vis[t]) continue; dis[t] = dis[u] + w[i]; get_dis(t,u); } } int calc(int x,int d){ cnt[0] = cnt[1] = cnt[2] = 0; dis[x] = d; get_dis(x,0); return cnt[1] * cnt[2] *2 + cnt[0] * cnt[0]; } void solve(int x){ ans += calc(x,0); vis[x]=1; for(int i=first[x];i;i=next[i]){ int t=to[i]; if(vis[t]) continue; ans -= calc(t,w[i]); rt = 0 , siz = size[t]; get_root(t,0); solve(rt); } } int main(){ n=read(); for(int i=1;i<n;i++){ int x=read(),y=read(),z=read()%3; add(x,y,z),add(y,x,z); } Maxson[0] = siz = n; get_root(1,0); solve(rt); int x = n * n , g = gcd(x,ans); printf("%d/%d\n",ans/g,x/g); return 0; }