hdu5449 Robot Dog (树形dp+倍增lca)

(警告:本篇博客包含大量人类本质内容)

先处理出来lca,然后就只需要知道从每个点到他的父亲、和从他的父亲到这个点的期望时间就可以了

我们设f[x]为x到他父亲的期望时间;g[x]为从x的父亲到x的期望时间(注意到这两个是不一样的)

只考虑怎么算f,g是类似的

从某个点想走到他父亲时,情况会有:直接走到;先走到某个儿子然后走回来,再走到父亲;先走到某个儿子然后走回来,再走到某个儿子然后走回来,再走到某个儿子然后走回来,....,然后走到父亲

假设x有k个儿子,每个儿子记为ch[1...k]

那我们能得出$f[x]=\frac{1}{k+1}+\sum\limits_{i=1}^{k}{\frac{f[ch[i]]+1}{k+1}}+\frac{k}{k+1}(\frac{1}{k+1}+\sum\limits_{i=1}^{k}{\frac{f[ch[i]]+1}{k+1}}+\frac{k}{k+1}(...$

意思是,有$\frac{1}{k+1}$的可能性直接走到,另外$\frac{1}{k+1}$先用1时间走错到儿子、然后再用儿子的那个期望时间走回来,并以$\frac{k}{k+1}$的可能性再次有$\frac{1}{k+1}$的可能性直接走到,另外$\frac{1}{k+1}$先用1时间走错到儿子、然后再用儿子的那个期望时间走回来,并以$\frac{k}{k+1}$的可能性再次...

把$\frac{1}{k+1}+\sum\limits_{i=1}^{k}{\frac{f[ch[i]]+1}{k+1}}$记为a,$\frac{k}{k+1}$,就有$f[x]=a+b(a+b(a+b(a+b(....=(1+b^1+b^2+...)a=\frac{a}{1-b}$(等比数列和的极限)

这样dfs一下(好几下),就可以算出f了,g同理(注意顺序,两次dfs分别算f和g,算f的时候先算孩子,算g的时候先算父亲),只不过是有可能走错到父亲

然后倍增记一记f和g的和,做lca就行了(注意路径的方向)

然后就wa了...

可以发现其实这些期望都是整数,因为$\frac{1}{1-b}=k+1$,而a的分母又都是k+1...所以改用long long,避免掉奇奇怪怪的精度问题,就可以过了..(怀疑是%.4lf是否四舍五入的问题,我的本地是会四舍五入的所以拍不出锅,但要是直接截取就锅了...)

  1 #include<bits/stdc++.h>
  2 #define pa pair<int,int>
  3 #define CLR(a,x) memset(a,x,sizeof(a))
  4 using namespace std;
  5 typedef long long ll;
  6 const int maxn=5e4+10;
  7 
  8 inline ll rd(){
  9     ll x=0;char c=getchar();int neg=1;
 10     while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();}
 11     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
 12     return x*neg;
 13 }
 14 
 15 int eg[maxn*2][2],egh[maxn],ect;
 16 int N,Q;
 17 ll f[maxn][20],g[maxn][20];
 18 int fa[maxn][20],dep[maxn];
 19 
 20 inline void adeg(int a,int b){
 21     eg[++ect][0]=b;eg[ect][1]=egh[a];egh[a]=ect;
 22 }
 23 
 24 void dfs1(int x){
 25     int k=0;
 26     for(int i=egh[x];i;i=eg[i][1]){
 27         int b=eg[i][0];if(b==fa[x][0]) continue;
 28         dep[b]=dep[x]+1;fa[b][0]=x;
 29         k++;dfs1(b);
 30     }
 31     if(fa[x][0]){
 32         ll alpha=1;
 33         for(int i=egh[x];i;i=eg[i][1]){
 34             int b=eg[i][0];if(b==fa[x][0]) continue;
 35             alpha+=f[b][0]+1;
 36         }
 37         f[x][0]=alpha;
 38     }
 39     
 40 }
 41 
 42 void dfs2(int x){
 43     int k=0;
 44     for(int i=egh[x];i;i=eg[i][1]){
 45         int b=eg[i][0];if(b==fa[x][0]) continue;
 46         k++;
 47     }
 48     if(fa[x][0]){
 49         ll alpha=1;
 50         for(int i=egh[x];i;i=eg[i][1]){
 51             int b=eg[i][0];if(b==fa[x][0]) continue;
 52             alpha+=f[b][0]+1;
 53         }
 54         for(int i=egh[x];i;i=eg[i][1]){
 55             int b=eg[i][0];if(b==fa[x][0]) continue;
 56             ll alphai=alpha-(f[b][0]+1);
 57             alphai+=g[x][0]+1;
 58             g[b][0]=alphai;
 59         }
 60     }else{
 61         ll alpha=1;
 62         for(int i=egh[x];i;i=eg[i][1]){
 63             int b=eg[i][0];if(b==fa[x][0]) continue;
 64             alpha+=f[b][0]+1;
 65         }
 66         for(int i=egh[x];i;i=eg[i][1]){
 67             int b=eg[i][0];if(b==fa[x][0]) continue;
 68             double alphai=alpha-(f[b][0]+1);
 69             g[b][0]=alphai;
 70         }
 71     }
 72     for(int i=egh[x];i;i=eg[i][1]){
 73         int b=eg[i][0];if(b==fa[x][0]) continue;
 74         dfs2(b);
 75     }
 76 //    printf("%d %lf %lf\n",x,f[x][0],g[x][0]);
 77 }
 78 
 79 void getst(int x){
 80     for(int i=0;fa[x][i]&&fa[fa[x][i]][i];i++){
 81         fa[x][i+1]=fa[fa[x][i]][i];
 82         f[x][i+1]=f[x][i]+f[fa[x][i]][i];
 83         g[x][i+1]=g[x][i]+g[fa[x][i]][i];
 84 //        printf("%d %d %d %lf %lf\n",x,i+1,fa[x][i+1],f[x][i+1],g[x][i+1]);
 85     }
 86     for(int i=egh[x];i;i=eg[i][1]){
 87         int b=eg[i][0];if(b==fa[x][0]) continue;
 88         getst(b);
 89     }
 90 }
 91 
 92 inline ll solve(int s,int t){
 93     ll re=0;
 94     if(dep[s]>dep[t]){
 95         for(int i=18;i>=0;i--){
 96             if(fa[s][i]&&dep[fa[s][i]]>=dep[t]){
 97                 re+=f[s][i],s=fa[s][i];
 98             }
 99         }
100 //        if(s==t) return re-f[s][0];
101     }else if(dep[t]>dep[s]){
102         for(int i=18;i>=0;i--){
103             if(fa[t][i]&&dep[fa[t][i]]>=dep[s]){
104                 re+=g[t][i],t=fa[t][i];
105             }
106         }
107 //        if(s==t) return re-g[t][0];
108     }
109     if(s==t) return re;
110     for(int i=18;i>=0;i--){
111         if(fa[s][i]&&fa[t][i]&&fa[s][i]!=fa[t][i]){
112             re+=f[s][i]+g[t][i];
113             s=fa[s][i],t=fa[t][i];
114         }
115     }re+=f[s][0]+g[t][0];
116     return re;
117 }
118 
119 int main(){
120     // freopen("5449.in","r",stdin);
121     // freopen("5449.out","w",stdout);
122     int i,j,k;
123     for(int T=rd();T;T--){
124         CLR(fa,0);CLR(dep,0);CLR(egh,0);ect=0;
125         CLR(f,0);CLR(g,0);
126         N=rd();
127         for(i=1;i<N;i++){
128             int a=rd()+1,b=rd()+1;
129             adeg(a,b);adeg(b,a);
130         }
131         dep[1]=1;dfs1(1);dfs2(1);
132         getst(1);
133         Q=rd();
134         for(i=1;i<=Q;i++){
135             int p=rd(),lst=rd()+1;
136             ll ans=0;
137             for(j=1;j<=p;j++){
138                 int now=rd()+1;
139                 ans+=solve(lst,now);
140                 lst=now;
141             }
142             printf("%lld.0000\n",ans);
143         }
144         if(T>1) printf("\n");
145     }
146     return 0;
147 }

 

转载于:https://www.cnblogs.com/Ressed/p/9748430.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值