2018中國大學生程序設計競賽 - 網絡選拔賽 1009 - Tree and Permutation 【dfs+樹上兩點距離和】
Tree and Permutation
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 619 Accepted Submission(s): 214
Problem Description
There are N vertices connected by N?1 edges, each edge has its own length.The set { 1,2,3,…,N } contains a total of N! unique permutations, let’s say the i
For the i-th permutation, it can be a traverse sequence of the tree with N vertices, which means we can go from the Pi,1-th vertex to the Pi,2-th vertex by the shortest path, then go to the Pi,3-th vertex ( also by the shortest path ) , and so on. Finally we’ll reach the Pi,N
Input
There are 10 test cases at most.The first line of each test case contains one integer N ( 1≤N≤105 ) .
For the next N?1 lines, each line contains three integer X, Y and L
Output
For each test case, print the answer module 109+7 in one line. Sample Input 3 1 2 1 2 3 1 3 1 2 1 1 3 2 Sample Output 16 24 Source 2018中國大學生程序設計競賽 - 網絡選拔賽
大概題意:
給一棵N個節點的樹, 求按N個節點全排列的順序走一遍這棵樹所得的路徑貢獻和。
解題思路:
對於所有按照全排列走過的路徑,打表會發現,每兩點之間的距離都出現了 (N-1)!次,所以我們只需要求出 所有兩點之間的距離之和就可以解得最後的答案了。
也就是說我們只需要求出 ∑dis(i, j) 最後 ∑dis(i, j) * (N-1)! 就是答案了。
∑dis(i, j) 的求法:
我們可以根據當前節點 root 和 它的父節點 fa 的邊 v 把一棵樹分成兩部分, 一部分是 以 fa 為根節點的子樹,一部分是以 root 為根節點的子樹(即除去這課子樹是另一部分)。
如果我們已經預先知道了 fa 到 這棵樹每個節點的距離和 sum_dis[ fa ], 以及以 root 為根節點的子樹的大小t_size[ root ] ,那麽 節點 root 到樹上其他節點的距離和我們可以通過 sum_dis[ fa ]轉化而來;
因為sum_dis[fa] 減去 v 對上面所分成的樹的兩部分的影響剩下的就是sum_dis[root] 即sum_dis[root] = sum_dis[fa] - (N-t_size[root])*v - t_size[root]*v ;
因此,我們第一步dfs把 1 到各個節點的距離和求出來,第二步通過對 1 的距離和轉換 把其他節點的距離和求出來,最後所有距離和求和得出答案。
AC code:
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #include <cmath> 5 #define ll long long int 6 #define mod 1000000007 7 #define INF 0x3f3f3f3f 8 using namespace std; 9 10 const int MAXN = 1e5+10; 11 struct date{ 12 int v, next, len; 13 }node[MAXN<<1]; 14 ll sum_dis[MAXN]; 15 int t_size[MAXN]; 16 int head[MAXN], cnt; 17 int N; 18 19 void init() 20 { 21 memset(head, -1, sizeof(head)); 22 cnt = 0 ; 23 memset(sum_dis, 0, sizeof(sum_dis)); 24 memset(t_size, 0, sizeof(t_size)); 25 } 26 void add(int from, int to, int weight) 27 { 28 node[++cnt].next = head[from]; 29 head[from] = cnt; 30 node[cnt].v = to; 31 node[cnt].len = weight; 32 } 33 void dfs(int root, int fa, ll dis) 34 { 35 sum_dis[1] = (sum_dis[1]%mod+dis%mod)%mod; 36 t_size[root] = 1; 37 for(int x = head[root]; x != -1; x =node[x].next) 38 { 39 if(node[x].v != fa) 40 { 41 dfs(node[x].v, root, (dis+node[x].len)%mod); 42 t_size[root]+=t_size[node[x].v]; 43 } 44 } 45 } 46 void trans(int root, int fa) 47 { 48 int vv; 49 for(int i = head[root]; i != -1; i= node[i].next) 50 { 51 vv = node[i].v; 52 if(node[i].v != fa){ 53 sum_dis[vv] = (sum_dis[root]%mod+((1ll*(N-2*t_size[vv])*node[i].len)%mod)%mod)%mod; 54 if(sum_dis[vv] < 0) sum_dis[vv] += mod; 55 trans(vv, root); 56 } 57 } 58 } 59 int main() 60 { 61 int f, t, w; 62 while(~scanf("%d", &N)) 63 { 64 init(); 65 for(int i = 1; i < N; i++) 66 { 67 scanf("%d%d%d", &f, &t, &w); 68 add(f, t, w); 69 add(t, f, w); 70 } 71 dfs(1, 0, 0); 72 trans(1, 0); 73 ll P = 1, ans = 0; 74 for(int i = 1; i < N; i++) 75 P = 1ll*P*i%mod; 76 for(int i = 1; i <= N; i++) 77 ans = (ans + sum_dis[i])%mod; 78 ans = ans*P%mod; 79 printf("%lld\n", ans); 80 } 81 return 0; 82 }View Code
2018中國大學生程序設計競賽 - 網絡選拔賽 1009 - Tree and Permutation 【dfs+樹上兩點距離和】