P2081 [NOI2012] 迷失游乐园

· · 个人记录

题意

数据范围

解析

const int maxn=1e5+7;
int n,m,u,v,l[maxn],son[maxn];
struct bian{
    int to,l;
    bian(){}
    bian(int _to,int _l){
        to=_to,l=_l;
    }
};
b_s<bian> e[maxn];

double dw[maxn];
void dfd(int x,int fa){
    for(bian a:e[x])
        if(a.to!=fa)
            ++son[x],dfd(a.to,x);
    for(bian a:e[x])
        if(a.to!=fa)
            dw[x]+=1.0*a.l+dw[a.to];
    if(son[x]) dw[x]/=1.0*son[x];
    return;
}

double up[maxn];
void dfu(int x,int fa){//注意一下,为了方便,我们在dfu中是站在父亲那里处理儿子 
    for(bian a:e[x])
        if(a.to!=fa){
            if(x==1){
                up[a.to]=dw[x]*son[x]-a.l-dw[a.to];
                if(son[fa]>1) up[a.to]/=(son[x]-1);
                up[a.to]+=1.0*a.l;
            }
            else
                up[a.to]=1.0*a.l+(up[x]+dw[x]*son[x]-a.l-dw[a.to])/son[x];
        }
    for(bian a:e[x])
        if(a.to!=fa)
            dfu(a.to,x);
    return;
}

double dp[maxn],ans;

int main(){
    n=rd(),m=rd();
    For(i,1,m){
        u=rd(),v=rd(),l[i]=rd();
        e[u]+=bian(v,l[i]),e[v]+=bian(u,l[i]);
    }
    dfd(1,1);//咱们就规定1是FA
    dfu(1,1);
    dp[1]=dw[1];
    For(i,2,n)
        dp[i]=(up[i]+dw[i]*son[i])/(son[i]+1);
    For(i,1,n) ans+=dp[i];
    ans/=1.0*n;
    printf("%.5lf",ans);
    return 0;
}
#include<bits/stdc++.h>
#define ll long long
#define us unsigned
#define b_s basic_string
#define For(i,a,b) for(int i=(a);i<=(b);++i)
#define foR(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
ll rd(){
    ll s=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)){s=(s<<3)+(s<<1)+(ch^48);if(ch!='\n') ch=getchar();}
    return s*f;
}
char wtst[66];
int wtps;
void wt(ll x){
    if(x<0) putchar('-'),x=-x;
    while(x>9) wtst[++wtps]=(x%10+'0'),x/=10;
    wtst[++wtps]=x+'0';
    while(wtps) putchar(wtst[wtps--]);
    return;
}
void wth(ll x){wt(x);putchar('\n');return;}
void wtk(ll x){wt(x);putchar(' ');return;}

const int maxn=1e5+7;
int n,m,u,v,l[maxn],son[maxn];
struct bian{
    int to,l;
    bian(){}
    bian(int _to,int _l){
        to=_to,l=_l;
    }
};
b_s<bian> e[maxn];

int prest[maxn],p,vis[maxn],cir[27],cnt;
bool flag,incir[maxn];
void predfs(int x,int fa){
    if(flag) return;
    prest[++p]=x;vis[x]=1;
    for(bian a:e[x]){
        if(a.to==fa) continue;
        if(vis[a.to]==0) predfs(a.to,x);
        else{
            flag=1;
            while(true){
                cir[++cnt]=prest[p];
                vis[prest[p]]=0,incir[prest[p]]=1;
                --p;
                if(prest[p+1]==a.to) return;
            }
        }
    }
    --p;vis[x]=0;
    return;
}

double dw[maxn];
void dfd(int x,int fa){
    for(bian a:e[x])
        if(a.to!=fa && !(incir[a.to] && incir[x]))//不允许从环上一点扩展到环上另一点(计算dw的时候可认为环上的所有边都不存在) 
            ++son[x],dfd(a.to,x);
    for(bian a:e[x])
        if(a.to!=fa && !(incir[a.to] && incir[x]))
            dw[x]+=1.0*a.l+dw[a.to];
    if(son[x]) dw[x]/=1.0*son[x];
    return;
}

double up[maxn];

double dff(int x,int fa,int FA){
    double ret=son[x]*dw[x];
    int chu=son[x];
    if(x==FA) ret=0.0,chu=0;
    for(bian a:e[x])
        if(a.to!=fa && a.to!=FA && incir[a.to] && incir[x])//从当前点走到另一个环上点,不允许回到起点 
            ++chu,ret+=dff(a.to,x,FA)+a.l;
    if(chu!=0) ret=ret/chu;
    return ret;
}

void dfu(int x,int fa){//注意一下,为了方便,我们在dfu中是站在父亲那里处理儿子 
    for(bian a:e[x])
        if(a.to!=fa && !(incir[a.to] && incir[x])){
            if(incir[x]){
                if(cnt==1 && x==1){//假基环树,这个是根节点1
                    up[a.to]=dw[x]*son[x]-a.l-dw[a.to];
                    if(son[fa]>1) up[a.to]/=(son[x]-1);
                    up[a.to]+=1.0*a.l;
                } 
                else up[a.to]=1.0*a.l+(2*up[x]+dw[x]*son[x]-a.l-dw[a.to])/(son[x]+1);
            }
            else
                up[a.to]=1.0*a.l+(up[x]+dw[x]*son[x]-a.l-dw[a.to])/son[x];
        }
    for(bian a:e[x])
        if(a.to!=fa && !(incir[a.to] && incir[x]))
            dfu(a.to,x);
    return;
}

double dp[maxn],ans;

int main(){
    n=rd(),m=rd();
    For(i,1,m){
        u=rd(),v=rd(),l[i]=rd();
        e[u]+=bian(v,l[i]),e[v]+=bian(u,l[i]);
    }

    predfs(1,1);
    if(cnt==0) cnt=1,cir[1]=1,incir[1]=1;
    For(i,1,cnt) dfd(cir[i],cir[i]);//从每个环上点开始,处理好它和它子树的dw
    For(i,1,cnt) up[cir[i]]=dff(cir[i],cir[i],cir[i]);//暴力处理环上每个点的up 
    For(i,1,cnt) dfu(cir[i],cir[i]);//站在父亲处理儿子 

    For(i,1,n){ 
        if(incir[i]){
            if(cnt==1) dp[i]=dw[i];
            else dp[i]=(up[i]*2+dw[i]*son[i])/(son[i]+2);
        }
        else 
            dp[i]=(up[i]+dw[i]*son[i])/(son[i]+1);
    }
    For(i,1,n) ans+=dp[i];
    ans/=1.0*n;
    printf("%.5lf",ans);
    return 0;
}

总结与反思

1.知识点

2.解题中的失误

3.其他