[Luogu 2656] 采蘑菇

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;
}

原文地址:https://www.cnblogs.com/YoungNeal/p/8647455.html

时间: 2024-08-06 23:58:07

[Luogu 2656] 采蘑菇的相关文章

洛谷2656 采蘑菇

本题地址:http://www.luogu.org/problem/show?pid=2656 题目描述 小胖和ZYR要去ESQMS森林采蘑菇.      ESQMS森林间有N个小树丛,M条小径,每条小径都是单向的,连接两个小树丛,上面都有一定数量的蘑菇.小胖和ZYR经过某条小径一次,可以采走这条路上所有的蘑菇.由于ESQMS森林是一片神奇的沃土,所以一条路上的蘑菇被采过后,又会长出一些新的蘑菇,数量为原来蘑菇的数量乘上这条路的“恢复系数”,再下取整.      比如,一条路上有4个蘑菇,这条路

Luogu P2656 采蘑菇

尽管是缩点的习题,思路也是在看了题解后才明白的. 首先,每个强连通分量内的点都是一定互通的,也就是可以完全把这里面的边都跑满,摘掉所有能摘的蘑菇.那么,考虑给每一个强连通分量化为的新点一个点权,代表摘光蘑菇能拿到的边权之和.然后,在新点之间保留原来的桥及其初始权值.(每一个桥一定只能跑一遍,否则说明这两个本应单向通行的分量之间有返回的路径,则二者可构成一个更大的分量.这个结论正是tarjan算法求有向图dcc的核心原理.)现在得到了一张新图,问题在于如何在一张包含点权.边权的DAG上求起始于定点

luogu P2056 采花

题目描述 萧芸斓是 Z国的公主,平时的一大爱好是采花. 今天天气晴朗,阳光明媚,公主清晨便去了皇宫中新建的花园采花.花园足够大,容纳了 n 朵花,花有 c 种颜色(用整数 1-c 表示) ,且花是排成一排的,以便于公主采花. 公主每次采花后会统计采到的花的颜色数, 颜色数越多她会越高兴! 同时, 她有一癖好,她不允许最后自己采到的花中,某一颜色的花只有一朵.为此,公主每采一朵花,要么此前已采到此颜色的花,要么有相当正确的直觉告诉她,她必能再次采到此颜色的花. 由于时间关系,公主只能走过花园连续的

【细节题 离线 树状数组】luoguP4919 Marisa采蘑菇

歧义差评:但是和题意理解一样了之后细节依然处理了很久,说明还是水平不够…… 题目描述 Marisa来到了森林之中,看到了一排nn个五颜六色的蘑菇,编号从1-n1−n,这些蘑菇的颜色分别为col[1],col[2]...col[n]col[1],col[2]...col[n]由于她很挑剔,所以她只会采那些"魔法蘑菇" 一个蘑菇被叫做"魔法蘑菇",当且仅当它在给定的某段区间内,并且在这段给定区间内与它颜色相同的蘑菇(包括它本身)的个数 与在这个给定区间外这种颜色的蘑菇的

采蘑菇

洛咕 题意:ESQMS森林间有N个小树丛,M条小径,每条小径都是单向的,连接两个小树丛,上面都有一定数量的蘑菇.小胖和ZYR经过某条小径一次,可以采走这条路上所有的蘑菇.由于ESQMS森林是一片神奇的沃土,所以一条路上的蘑菇被采过后,又会长出一些新的蘑菇,数量为原来蘑菇的数量乘上这条路的"恢复系数",向下取整.比如,一条路上有4个蘑菇,这条路的"恢复系数"为0.7,则第一~四次经过这条路径所能采到的蘑菇数量分别为4,2,1,0.现在,小胖和ZYR从S号小树丛出发,求

[Luogu2656]采蘑菇

题目大意: 给你一个有向图,每条边有一个边权w以及恢复系数k, 你从s点出发乱走,经过某条边时会获得相应的收益w,而当第二次经过这条边时相应的收益为w*k下取整. 问你最大能获得的收益为多少? 思路: 缩点+DP. 首先跑一下Tarjan(只要从s开始跑,因为没跑到的地方肯定和答案没关系). 对于每个强连通分量,我们算一下经过这个强联通分量能获得的总收益sum(就是拼命在这上面绕圈圈). 把原图缩为一个DAG,然后就可以DP了. 设当前点为i,后继结点为j,边权为w,j的SCC的总收益为sum[

4.3 省选模拟赛 采蘑菇 点分治

给出一棵树 每个点都有一个颜色ci 问 从i号点出发到任意一个点的路径上本质不同的颜色之和. \(n\leq 300000\) 光线性扫描时不行的 显然有\(n^2\)的暴力. 考虑树是一条链的时候怎么做? 可以发现先求出1的答案然后维护换根的过程 记录每个点颜色的pre 前驱 nex后继很容易通过分类讨论得到答案. 考虑树的时候怎么做?还是维护换根的过程 当两个点颜色相同的时候 答案显然一样,当不同的时候 可以分析得出 要查自己子树内没有自己父亲颜色的祖先的节点个数.还要查 自己子树之外没有自

金正B872插卡音箱内存卡音频文件清单 =MID

编号 1 Alone_AlanWa2 曾国藩的处世智慧耐得千事3 Faded_AlanWa4 SingMeToSlee5 一千零一个愿望_一人一首6 一场游戏一场梦港台版_一7 一天一天等下去烟火_一人8 一天一点爱恋港_一人一首9 一生不变粤_一人一首成名10 一起走过的日子港台版_一11 丁文琪不说_一人一首成名12 万芳新不了情_一人一首成13 万芳猜心精选_一人一首成14 上海滩_一人一首成名曲15 不装饰你的梦港台版版_一16 为爱疯狂港台版_一人一首17 乌苏里船歌大陆版_一人一18

[2019CSP-S赛前训练][CF894E] Ralph and Mushrooms

题目链接:https://www.luogu.org/problem/CF894E 题目大意 Ralph打算去蘑菇森林采蘑菇. 蘑菇森林里有n个蘑菇丛,有m条有向的路连接这些丛林(可能连向自己,也可能两个丛林之间有多条路).经过某条路时,Ralph可以采走这条路上的全部蘑菇.然而,这是一片神奇的蘑菇森林,蘑菇被采走后会重新长出来一些.但是,第k次走过这条路后,这条路上重新长出的蘑菇会比上次少k.(举个栗子,第一次有w个蘑菇,第二次有w-1个蘑菇,第三次有w-1-2个蘑菇,以此类推--)(还有,蘑