Details

其实细节并不是很多。
因为我们要倒着做,所以直接给连出去的所有边的那一段排一个序就好了。
一开始我们的所有边按照起点的序号排序,那么我们就可以直接排序那一段了。
我们的起点a,用ll[a],rr[a]存它连出去的边排序之后的两个端点,那么我们就可以排序这一段了。

Code

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
using namespace std;
const int maxn=100005;
int i,j,k,t,n,m,ans,num;
int l[maxn*2],r[maxn*2];
double f[maxn*2];
struct node{
int a,b,c;
double p,zhi;
}bian[maxn*2];
bool cmp(node x,node y){
return x.a<y.a;
}
bool cmp1(node x,node y){
return x.zhi>y.zhi;
}
int main(){
scanf("%d%d",&n,&m);
fo(i,1,n-1){
num++;
scanf("%d",&bian[num].c);
bian[num].p=1;bian[num].a=i;bian[num].b=i+1;
}
fo(i,1,m){
num++;
scanf("%d%d%lf%d",&bian[num].a,&bian[num].b,&bian[num].p,&bian[num].c);
}
sort(bian+1,bian+num+1,cmp);
j=0;
fo(i,1,num+1){
if(bian[i-1].a!=bian[i].a){
r[j]=i-1;
j++;
l[j]=i;
}
}
fod(i,n,1){
double p=1;
fo(j,l[i],r[i])bian[j].zhi=bian[j].p/(bian[j].c+bian[j].p*f[bian[j].b]);
if (l[i]<=r[i])sort(bian+l[i],bian+r[i]+1,cmp1);
fo(j,l[i],r[i]){
f[i]+=p*(f[bian[j].b]*bian[j].p+bian[j].c);
p=p*(1-bian[j].p);
}
}
printf("%.2f\n",f[1]);
}