1. 程式人生 > >luogu P2634 [國家集訓隊]聰聰可可

luogu P2634 [國家集訓隊]聰聰可可

傳送門

上來想的樹形dp怎麼破......

因為點分治做到的就是把樹上所有路徑問題轉化成過一點的路徑問題

所以可以分開統計過某一點的路徑

記錄%3之後的路徑條數就可以做 分析一下就出來了

這裡注意向下遞迴的時候要把方案數減掉 也就是74行那個ans-calc()

剩下的套點分治板子就星

Code:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define ms(a,b) memset(a,b,sizeof a)
 5 #define rep(i,a,n) for(int i = a;i <= n;i++)
 6
#define per(i,n,a) for(int i = n;i >= a;i--) 7 #define inf 2147483647 8 using namespace std; 9 typedef long long ll; 10 ll read() { 11 ll as = 0,fu = 1; 12 char c = getchar(); 13 while(c < '0' || c > '9') { 14 if(c == '-') fu = -1; 15 c = getchar(); 16 } 17 while
(c >= '0' && c <= '9') { 18 as = as * 10 + c - '0'; 19 c = getchar(); 20 } 21 return as * fu; 22 } 23 //head 24 const int N = 100003; 25 int n,m,q[N]; 26 int head[N],mo[N<<1],nxt[N<<1],cst[N<<1],cnt; 27 void addd(int x,int y,int w) { 28 nxt[++cnt] = head[x],head[x] = cnt;
29 mo[cnt] = y,cst[cnt] = w; 30 } 31 void add(int x,int y) { 32 int w = read() % 3; 33 if(x^y) addd(x,y,w),addd(y,x,w); 34 } 35 36 int sze[N]; 37 bool vis[N]; 38 int sum,rt,maxx[N]; 39 void getroot(int x,int f) { 40 sze[x] = 1,maxx[x] = 0; 41 for(int i = head[x];i;i = nxt[i]) { 42 int sn = mo[i]; 43 if(vis[sn] || sn == f) continue; 44 getroot(sn,x),sze[x] += sze[sn]; 45 maxx[x] = max(maxx[x],sze[sn]); 46 } 47 maxx[x] = max(maxx[x],sum - sze[x]); 48 if(maxx[x] < maxx[rt]) rt = x; 49 } 50 51 int dis[N]; 52 int con[3]; 53 void getdis(int x,int f) { 54 con[dis[x]]++; 55 for(int i = head[x];i;i = nxt[i]) { 56 int sn = mo[i]; 57 if(sn == f || vis[sn]) continue; 58 dis[sn] = (dis[x] + cst[i]) % 3; 59 getdis(sn,x); 60 } 61 } 62 63 int ans; 64 int calc(int x,int d) { 65 dis[x] = d,ms(con,0),getdis(x,x); 66 return con[0] * con[0] + con[1] * con[2] * 2; 67 } 68 69 void solve(int x) { 70 vis[x] = 1,ans += calc(x,0); 71 for(int i = head[x];i;i = nxt[i]) { 72 int sn = mo[i]; 73 if(vis[sn]) continue; 74 ans -= calc(sn,cst[i]); 75 sum = sze[sn],maxx[rt = 0] = inf; 76 getroot(sn,sn),solve(rt); 77 } 78 } 79 80 int gcd(int x,int y) {return y ? gcd(y,x%y) : x;} 81 82 int main() { 83 n = read(); 84 rep(i,2,n) add(read(),read()); 85 sum = n,maxx[rt = 0] = inf; 86 getroot(1,1),solve(rt); 87 int d = gcd(ans,n*n); 88 printf("%d/%d\n",ans/d,n*n/d); 89 return 0; 90 }