P1235 血缘关系

f[i][j]表示i、j的亲缘关系。
f[i][j]=(f[i][fa[j]]+f[i][mo[j]])/2或f[i][j]=(f[fa[i]][j]+f[mo[i]][j])/2
按拓扑序推一遍就好了。
听说有高精度小数。
整天邻接表不开两倍内存,还调半天调不出,跟个傻逼一样。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define rep(i,j,k) for(i=j;i<=k;++i)
#define per(i,j,k) for(i=j;i>=k;--i)
#define sqr(x) ((x)*(x))
#define G getchar()
#define LL long long
#define pll pair<LL,LL>
#define mkp make_pair
#define X first
#define Y second
#define N 305
int n,m,fa[N],mo[N];
int he[N],ne[N<<1],to[N<<1],tot;
int q[N],in[N];
struct DATA{short dat[N];int ln;}f[N][N];
DATA operator +(DATA x,DATA y){
    x.ln=max(x.ln,y.ln);
    int i;per(i,x.ln,1)
        if((x.dat[i]+=y.dat[i])>9)++x.dat[i-1],x.dat[i]-=10;
    x.dat[0]+=y.dat[0];
    while(x.ln&&!x.dat[x.ln])--x.ln;
    return x;
}
DATA div2(DATA x){
    int i;
    rep(i,0,x.ln){
        if(x.dat[i]&1)x.dat[i+1]+=10;
        x.dat[i]>>=1;
    }
    if(x.dat[x.ln+1])x.dat[++x.ln]=5;
    return x;
}
void add(int x,int y){
    to[++tot]=y;ne[tot]=he[x];he[x]=tot;
}
int read(){
    int x=0;char ch=G;
    while(ch<48||ch>57)ch=G;
    for(;ch>47&&ch<58;ch=G)x=x*10+ch-48;
    return x;
}
void BFS(){
    int Ft=1,Rr=1,u,v,i;
    rep(i,1,n){
        if(!in[i])q[Rr++]=i;f[i][i].dat[0]=1;
    }
    while(Ft<Rr){
        u=q[Ft++];
        per(i,Ft-2,1){
            v=q[i];f[u][v]=f[v][u]=div2(f[v][fa[u]]+f[v][mo[u]]);
        }
        for(i=he[u];i;i=ne[i])if(--in[v=to[i]]==0)q[Rr++]=v;
    }
}
void write(DATA x){
    printf("%d",x.dat[0]*100+x.dat[1]*10+x.dat[2]);int i;
    if(x.ln>2){
        putchar('.');
        rep(i,3,x.ln)printf("%d",x.dat[i]);
    }
    puts("%");
}
int main(){
    int i,x,Q,y;
    n=read();m=read();
    while(m--){
        in[x=read()]=2;fa[x]=read();mo[x]=read();
        add(fa[x],x);add(mo[x],x);
    }
    BFS();
    for(Q=read();Q--;){
        x=read();y=read();write(f[x][y]);
    }
    return 0;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值