codeforces Goodbye 2014 D题(树上统计,DFS)
2015-01-01 01:35:27
思路:这道题是有母题的....hdu 2376
比赛时花了一个多小时想....后来sb地搞成了树形DP,死活不过(逃QAQ.....
其实就是计算每条边的对结果的贡献,在n个点里选3个点的总情况数是total = n * (n - 1) * (n - 2) / 6
选某条边作为要建的边的情况数如何计算呢?设这条边的某一侧的子树大小为sz,那么应该是 sz * (n - sz) * (n - 2),先在两边任选一个点,然后在剩余的(n-2)个点中再任选一个点。
某条边的贡献:w[i] * sz * (n - sz) * (n - 2) / total
至于删边同理,处理所删掉部分的负贡献。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 int a,b,n,q,sz[100010]; 5 ll dtr[100010]; 6 vector<int> g[100010]; 7 struct edge{ int u,v,c;}e[200010]; 8 void Dfs(int p,int fa){ 9 sz[p] = 1; 10 for(int i = 0; i < g[p].size(); ++i) if(g[p][i] != fa){ 11 int v = g[p][i]; 12 Dfs(v,p),sz[p] += sz[v]; 13 } 14 } 15 int main(){ 16 scanf("%d",&n); 17 for(int i = 1; i < n; ++i){ 18 scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].c); 19 g[e[i].u].push_back(e[i].v); 20 g[e[i].v].push_back(e[i].u); 21 } 22 Dfs(1,0); 23 double ans = 0.0; 24 ll total = (ll)n * (n - 1) * (n - 2) / 6LL; 25 for(int i = 1; i < n; ++i){ 26 ll siz = min(sz[e[i].u],sz[e[i].v]); 27 dtr[i] = siz * (n - siz) * (n - 2); 28 ans += (double)dtr[i] * e[i].c / total; 29 } 30 for(scanf("%d",&q); q; --q){ 31 scanf("%d%d",&a,&b); 32 ans -= (double)dtr[a] * (e[a].c - b) / total,e[a].c = b; 33 printf("%.10f\n",ans); 34 } 35 return 0; 36 }