1. 程式人生 > >[Luogu 2656] 采蘑菇

[Luogu 2656] 采蘑菇

AR iostream post you 一個 -- 數據 edge cstring

Description

小胖和ZYR要去ESQMS森林采蘑菇。

ESQMS森林間有N個小樹叢,M條小徑,每條小徑都是單向的,連接兩個小樹叢,上面都有一定數量的蘑菇。小胖和ZYR經過某條小徑一次,可以采走這條路上所有的蘑菇。由於ESQMS森林是一片神奇的沃土,所以一條路上的蘑菇被采過後,又會長出一些新的蘑菇,數量為原來蘑菇的數量乘上這條路的“恢復系數”,再下取整。

比如,一條路上有4個蘑菇,這條路的“恢復系數”為0.7,則第一~四次經過這條路徑所能采到的蘑菇數量分別為4,2,1,0.

現在,小胖和ZYR從S號小樹叢出發,求他們最多能采到多少蘑菇。

對於30%的數據,N<=7,M<=15

另有30%的數據,滿足所有“恢復系數”為0

對於100%的數據,N<=80,000,M<=200,000,0.1<=恢復系數<=0.8且僅有一位小數,1<=S<=N.

Input

第一行,N和M

第2……M+1行,每行4個數字,分別表示一條小路的起點,終點,初始蘑菇數,恢復系數。

第M+2行,一個數字S

Output

一個數字,表示最多能采到多少蘑菇,在int32範圍內。

Solution

強聯通分量縮點。

記錄每個 SCC 內部把所有的邊都壓榨完之後的權值和 sze[]

然後拓撲跑最長路即可。

upd:第一遍 wa 是因為用了一種自作聰明的在 Tarjan 過程就求 sze 的做法,但是是錯的,因為一個包含 n 個點的 SCC 不一定只有 n 條邊。

第二遍 wa 是因為數據有自環,所以在計算 sze 的時候不能根據起點和終點求,而是要遍歷每條邊。

Code

// By YoungNeal
#include<queue> #include<cstdio> #include<cstring> #include<iostream> #define N 80005 #define M 200005 int maxn; int n,m,s; bool in[N]; int sze[N]; int dis[N]; int deg[N]; int head2[N]; int stk[N],top; int cnt,sum,tot;
int c[N],head[N]; int dfn[N],low[N]; struct Edge{ int to,nxt,dis,js; }edge[M],edge2[M]; void add(int x,int y,int z,int k){ edge[++cnt].to=y; edge[cnt].nxt=head[x]; edge[cnt].dis=z; edge[cnt].js=k; head[x]=cnt; } void add_c(int x,int y,int z){ edge2[++cnt].to=y; edge2[cnt].nxt=head2[x]; edge2[cnt].dis=z; head2[x]=cnt; } void tarjan(int now){ dfn[now]=low[now]=++sum; stk[++top]=now;in[now]=1; for(int i=head[now];i;i=edge[i].nxt){ int to=edge[i].to; if(!dfn[to]) tarjan(to),low[now]=std::min(low[now],low[to]); else if(in[to]) low[now]=std::min(low[now],low[to]); } if(dfn[now]==low[now]){ int y;tot++; do{ y=stk[top--]; c[y]=tot,in[y]=0; }while(y!=now); } } int calc(int a,double b){ int ans=0; while(a){ ans+=a; a*=b; } return ans; } void toposort(){ std::queue<int> topo; for(int i=1;i<=tot;i++) dis[i]=-2e9; dis[c[s]]=sze[c[s]]; maxn=dis[c[s]]; for(int i=1;i<=tot;i++){ if(!deg[i]) topo.push(i); } while(topo.size()){ int u=topo.front();topo.pop(); for(int i=head2[u];i;i=edge2[i].nxt){ int to=edge2[i].to; dis[to]=std::max(dis[to],dis[u]+sze[to]+edge2[i].dis); deg[to]--; if(!deg[to]) topo.push(to); } } for(int i=1;i<=tot;i++) maxn=std::max(maxn,dis[i]); } signed main(){ scanf("%d%d",&n,&m); for(int a,b,c,i=1;i<=m;i++){ double x; scanf("%d%d%d%lf",&a,&b,&c,&x); int js=calc(c,x); add(a,b,c,js); } scanf("%d",&s); cnt=0; for(int i=1;i<=n;i++){ if(!dfn[i]) tarjan(i); } for(int x=1;x<=n;x++){ for(int i=head[x];i;i=edge[i].nxt){ int to=edge[i].to; if(c[x]!=c[to]) continue; sze[c[to]]+=edge[i].js; } } for(int x=1;x<=n;x++){ for(int i=head[x];i;i=edge[i].nxt){ int to=edge[i].to; if(c[x]==c[to]) continue; add_c(c[x],c[to],edge[i].dis); deg[c[to]]++; } } toposort(); printf("%d\n",maxn); return 0; }

[Luogu 2656] 采蘑菇