聰聰和可但是兄弟倆,他們倆常常爲了一些雜事打起來,例如家中只剩下最後一根冰棍而兩人都想吃、兩我的都想玩兒電腦(但是他們家只有一臺電腦)……遇到這種問題,通常狀況下石頭剪刀布就行了,但是他們已經玩兒膩了這種低智商的遊戲。node
他們的爸爸快被他們的爭吵煩死了,因此他發明了一個新遊戲:由爸爸在紙上畫n個「點」,並用n-1條「邊」把這n個「點」剛好連通(其實這就是一棵樹)。而且每條「邊」上都有一個數。接下來由聰聰和可可分別隨即選一個點(固然他們選點時是看不到這棵樹的),若是兩個點之間全部邊上數的和加起來剛好是3的倍數,則判聰聰贏,不然可可贏。c++
聰聰很是愛思考問題,在每次遊戲後都會仔細研究這棵樹,但願知道對於這張圖本身的獲勝機率是多少。現請你幫忙求出這個值以驗證聰聰的答案是否正確。網絡
輸入的第1行包含1個正整數n。後面n-1行,每行3個整數x、y、w,表示x號點和y號點之間有一條邊,上面的數是w。優化
以即約分數形式輸出這個機率(即「a/b」的形式,其中a和b必須互質。若是機率爲1,輸出「1/1」)。spa
5 1 2 1 1 3 2 1 4 1 2 5 3
13/25
【樣例說明】code
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)。orm
【數據規模】blog
對於100%的數據,n<=20000。遊戲
題意就是找樹上任意兩點路徑爲3的倍數的路徑數,除以全部路徑數。get
點分治,最後兩組數據怎麼也過不了,今天過了。
換了個讀入掛,也不行,手動吸氧過了。
不知道爲何總是超時,有點躁。
關於C++手動開O2優化:
O2優化能使程序的編譯效率大大提高
從而減小程序的運行時間,達到優化的效果。
C++程序中的O2開關以下所示:
#pragma GCC optimize(2)
一開始手動吸氧也沒過,後來可能網絡穩了,試了不少次都過了。
代碼:
1 //點分治 2 #include<bits/stdc++.h> 3 using namespace std; 4 #define fin freopen("in.txt", "r", stdin) 5 #define fout freopen("out.txt", "w", stdout) 6 #define FI(n) FastIO::read(n) 7 #pragma GCC optimize(2)//O2優化,手動吸氧才過。。。 8 typedef long long ll; 9 const int inf=0x3f3f3f3f; 10 const int maxn=2e4+10; 11 const int maxm=1e7+10; 12 const int mod=3; 13 14 int head[maxn<<1],tot; 15 int root,allnode,n,m,k; 16 int vis[maxn],dis[maxn],siz[maxn],maxv[maxn];//maxv爲重心節點 17 int ans[maxn]; 18 ll sum=0; 19 20 //namespace IO{ 21 // char buf[1<<15],*S,*T; 22 // inline char gc(){ 23 // if (S==T){ 24 // T=(S=buf)+fread(buf,1,1<<15,stdin); 25 // if (S==T)return EOF; 26 // } 27 // return *S++; 28 // } 29 // inline int read(){ 30 // int x; bool f; char c; 31 // for(f=0;(c=gc())<'0'||c>'9';f=c=='-'); 32 // for(x=c^'0';(c=gc())>='0'&&c<='9';x=(x<<3)+(x<<1)+(c^'0')); 33 // return f?-x:x; 34 // } 35 // inline long long readll(){ 36 // long long x;bool f;char c; 37 // for(f=0;(c=gc())<'0'||c>'9';f=c=='-'); 38 // for(x=c^'0';(c=gc())>='0'&&c<='9';x=(x<<3)+(x<<1)+(c^'0')); 39 // return f?-x:x; 40 // } 41 //} 42 //using IO::read; 43 //using IO::readll; 44 45 namespace FastIO {//讀入掛 46 const int SIZE = 1 << 16; 47 char buf[SIZE], obuf[SIZE], str[60]; 48 int bi = SIZE, bn = SIZE, opt; 49 int read(char *s) { 50 while (bn) { 51 for (; bi < bn && buf[bi] <= ' '; bi++); 52 if (bi < bn) break; 53 bn = fread(buf, 1, SIZE, stdin); 54 bi = 0; 55 } 56 int sn = 0; 57 while (bn) { 58 for (; bi < bn && buf[bi] > ' '; bi++) s[sn++] = buf[bi]; 59 if (bi < bn) break; 60 bn = fread(buf, 1, SIZE, stdin); 61 bi = 0; 62 } 63 s[sn] = 0; 64 return sn; 65 } 66 bool read(int& x) { 67 int n = read(str), bf; 68 69 if (!n) return 0; 70 int i = 0; if (str[i] == '-') bf = -1, i++; else bf = 1; 71 for (x = 0; i < n; i++) x = x * 10 + str[i] - '0'; 72 if (bf < 0) x = -x; 73 return 1; 74 } 75 }; 76 77 ll gcd(ll a,ll b) 78 { 79 return b==0?a:gcd(b,a%b); 80 } 81 82 struct node{ 83 int to,next,val; 84 }edge[maxn<<1]; 85 86 void add(int u,int v,int w)//前向星存圖 87 { 88 edge[tot].to=v; 89 edge[tot].next=head[u]; 90 edge[tot].val=w; 91 head[u]=tot++; 92 } 93 94 void init()//初始化 95 { 96 memset(head,-1,sizeof head); 97 memset(vis,0,sizeof vis); 98 tot=0; 99 } 100 101 void get_root(int u,int father)//求重心 102 { 103 siz[u]=1;maxv[u]=0; 104 for(int i=head[u];~i;i=edge[i].next){ 105 int v=edge[i].to; 106 if(v==father||vis[v]) continue; 107 get_root(v,u); 108 siz[u]+=siz[v]; 109 maxv[u]=max(maxv[u],siz[v]); 110 } 111 maxv[u]=max(maxv[u],allnode-siz[u]);//保存節點size 112 if(maxv[u]<maxv[root]) root=u;//更新保存當前子樹的重心 113 } 114 115 void get_dis(int u,int father)//獲取子樹全部節點與根的距離 116 { 117 ans[dis[u]%mod]++;//保存數量 118 for(int i=head[u];~i;i=edge[i].next){ 119 int v=edge[i].to; 120 if(v==father||vis[v]) continue; 121 int w=edge[i].val; 122 dis[v]=(dis[u]+w)%mod; 123 get_dis(v,u); 124 } 125 } 126 127 ll cal(int u,int now)//每一棵子樹的計算 128 { 129 ans[0]=ans[1]=ans[2]=0; 130 dis[u]=now; 131 get_dis(u,0); 132 ll ret=ans[1]*ans[2]*2+ans[0]*(ans[0]-1)+ans[0];//1的加上2的+0的 133 return ret; 134 } 135 136 void solve(int u) 137 { 138 sum+=cal(u,0);//全部知足的 139 vis[u]=1; 140 for(int i=head[u];~i;i=edge[i].next){ 141 int v=edge[i].to; 142 int w=edge[i].val; 143 if(vis[v]) continue; 144 sum-=cal(v,w);//去掉子樹的,容斥思想。 145 allnode=siz[v]; 146 root=0; 147 get_root(v,u); 148 solve(root); 149 } 150 } 151 152 int main() 153 { 154 // n=read(); 155 FI(n); 156 init(); 157 for(int i=1;i<n;i++){ 158 int u,v,w; 159 FI(u),FI(v),FI(w); 160 add(u,v,w); 161 add(v,u,w); 162 } 163 root=0;allnode=n;maxv[0]=inf; 164 get_root(1,0); 165 solve(root); 166 ll num=n*n; 167 ll GCD=gcd(sum,num); 168 printf("%lld/%lld\n",sum/GCD,num/GCD); 169 }