zoukankan      html  css  js  c++  java
  • Good Bye 2014 D. New Year Santa Network 图的邻接表存储不用vector,dfs,概率,期望,想法

    题目链接:

    http://codeforces.com/problemset/problem/500/D

    题意:

    有n(1e5)个城市和n-1条边,构成一棵树。

    同时我们会有q(1e5)次修改操作
    对于每次操作,我们把一条边的边权减小到w
    每次操作之后,我们任意选3个点,问你这三个点之间3条路径的距离之和的期望是多少

    思路:

    http://blog.csdn.net/snowy_smile/article/details/50942412

    首先,我们全部都不考虑顺序。n个点选出3个,方案数为C(n,3)

    然后,我们不妨以1为树根,然后研究每条边
    我们可以通过dfs,得到每条边的上下各有多少个点。
    假如说在一条边i的上面有up[i]个点,下面有dn[i]个点。
    那么,我们就有C(up[i],1)*C(dn[i],2)+C(up[i],2)*C(dn[i],1)种方案选到这条边
    于是,我们累计每条边被选中的方案*边权,再/=方案数,答案就出来啦!

    然而,我这样算出来的答案有问题,只有实际答案的一半,为什么呢?
    因为有C(up[i],1)*C(dn[i],2)+C(up[i],2)*C(dn[i],1)种方案选到这条边
    而每个方案中,这个边权都被我们走了2次。于是最后再*2就可以啦

    学习到了这种邻接表的存图方式: 邻接表的存图方式(不用vector正常的方式),可以给每条双向边编号。这样就能够与最初给的边的编号联系起来【编号的边/2是真正的边的编号】,给每条边做额外的处理! 这是vector做不到的。

     1 memset(first,0,sizeof(first);
     2 
     3 void add(int x,int y,int ww){
     4     s[++id] = y;
     5     w[id] = ww;
     6     nxt[id] = first[x];
     7     first[x] = id;
     8 }
     9 
    10 for(int z=first[u]; z; z=nxt[z])  // 这样遍历,也可以给first初始化为-1,z变成~z

    代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 #define MS(a) memset(a,0,sizeof(a))
     5 #define MP make_pair
     6 #define PB push_back
     7 const int INF = 0x3f3f3f3f;
     8 const ll INFLL = 0x3f3f3f3f3f3f3f3fLL;
     9 inline ll read(){
    10     ll x=0,f=1;char ch=getchar();
    11     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    12     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    13     return x*f;
    14 }
    15 //////////////////////////////////////////////////////////////////////////
    16 const int maxn = 2e5+10;
    17 
    18 int n,id;
    19 int up[maxn],dn[maxn],sz[maxn],first[maxn],nxt[maxn],s[maxn],w[maxn];
    20 double ans;
    21 
    22 void add(int x,int y,int ww){
    23     s[++id] = y;
    24     w[id] = ww;
    25     nxt[id] = first[x];
    26     first[x] = id;
    27 }
    28 
    29 double C2(ll x){
    30     return x*(x-1)/2.0;
    31 }
    32 
    33 double C3(ll x){
    34     return x*(x-1)*(x-2)/6.0;
    35 }
    36 
    37 void dfs(int u,int fa){
    38     sz[u] = 1;
    39     for(int z=first[u]; z; z=nxt[z]){
    40         int v = s[z];
    41         if(v == fa) continue;
    42         dfs(v,u);
    43         sz[u] += sz[v];
    44         int zz = z/2; // zz是真的边,z是双向边的编号,所以/2
    45         dn[zz] = sz[v];
    46         up[zz] = n-sz[v];
    47         ans += (C2(up[zz])*dn[zz]+up[zz]*C2(dn[zz]))*w[z];
    48     }
    49 }
    50 
    51 int main(){
    52     cin >> n; id = 1;
    53     for(int i=1; i<n; i++){
    54         int u,v,w; cin>>u>>v>>w;
    55         add(u,v,w);
    56         add(v,u,w);
    57     }
    58 
    59     ans = 0;
    60     dfs(1,-1);
    61 
    62     int q = read();
    63     for(int i=0; i<q; i++){
    64         int num,ww; cin>>num>>ww;
    65         ans -= (C2(up[num])*dn[num] + up[num]*C2(dn[num])) * (double)(w[num*2]-ww);
    66         w[num*2] = ww;
    67         printf("%.10f
    ",ans*2/C3(n));
    68     }
    69 
    70 
    71     return 0;
    72 }
  • 相关阅读:
    Python合集之Python正则表达式(三)
    Python合集之Python正则表达式(一)
    Python合集之Python字符串编码转换
    Python合集之Python字符串常用操作(五)
    Python合集之Python字符串常用操作(四)
    【EFCORE笔记】数据库SQL操作日志记录
    【EFCORE笔记】捕获审计日志数据
    【EFCORE笔记】数据库提供程序优化与单元测试
    【EFCORE笔记】仓储与工作单元模式
    【EFCORE笔记】属性变更事件追踪策略
  • 原文地址:https://www.cnblogs.com/yxg123123/p/6905957.html
Copyright © 2011-2022 走看看