题目大意

约翰有\(n\)块草场,编号\(1\)到\(n\),这些草场由若干条单行道相连。奶牛贝西是美味牧草的鉴赏家,她想到达尽可能多的草场去品尝牧草。

贝西总是从\(1\)号草场出发,最后回到\(1\)号草场。她想经过尽可能多的草场,贝西在通一个草场只吃一次草,所以一个草场可以经过多次。因为草场是单行道连接,这给贝西的品鉴工作带来了很大的不便,贝西想偷偷逆向行走一次,但最多只能有一次逆行。问,贝西最多能吃到多少个草场的牧草。

\(n,m\le 10^5\)

QwQ一开始看这个题 没有思路呀

首先一定是\(tarjan\)消环,对吧

我们可以考虑,如果只能反向走一条边,那我们可以枚举这个边呀,然后算一算\(ans\)

那么对于一条边\(u->v\),如果我们选择反向走,我们能获得的收益是\(val[v]+valn[u]-sval[1]\) 其中\(val[x]\)表示从1到x的最大收益,\(valn[x]\)表示\(x\)到1的最大收益(这个可以通过建反图来算)

之所以减去\(sval[1]\),因为1这个联通快的贡献会算两边,按照题意,应该只算一遍。

为什么这样是对,为什么可以保证没有别的点的贡献被算两遍。

我们可以这么考虑,假设存在一个联通快他的贡献被计算了两次,那么他一定能到1,也能从1到,那么就说明存在环,但是因为我们在一开始\(tarjan\)缩点过,所以不会存在这么一个点,所以这样计算贡献是没有错的

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue> using namespace std; inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
} const int maxn = 1e5+1e2;
const int maxm = 1e6+1e2; int point[maxn],nxt[maxm],to[maxm],sval[maxn];
int s[maxn],top;
int bel[maxn],roo[maxn];
int tot;
int cnt;
int n,m;
int x[maxm],y[maxm];
int low[maxn],dfn[maxn];
int vis[maxn],scc; void addedge(int x,int y)
{
nxt[++cnt]=point[x];
to[cnt]=y;
point[x]=cnt;
} void tarjan(int x)
{
dfn[x]=low[x]=++tot;
s[++top]=x;
vis[x]=1;
for (int i=point[x];i;i=nxt[i])
{
int p = to [i];
if (!dfn[p])
{
tarjan(p);
low[x]=min(low[x],low[p]);
}
else
if(vis[p]) low[x]=min(low[x],dfn[p]);
}
if (low[x]==dfn[x])
{
scc++;
while (s[top+1]!=x)
{
//++scc;
bel[s[top]]=scc;
roo[s[top]]=x;
sval[scc]++;
vis[s[top]]=0;
top--;
}
}
} int num[maxm];
int dis[maxn],disn[maxn]; queue<int> q; void spfa(int s)
{
memset(dis,0,sizeof(dis));
memset(vis,0,sizeof(vis));
vis[s]=1;
dis[s]=sval[bel[s]];
q.push(s);
while (!q.empty()){
int x = q.front();
q.pop();
vis[x]=0;
for (int i=point[x];i;i=nxt[i])
{
int p = to[i];
if (dis[p]<dis[x]+sval[bel[p]])
{
dis[p]=dis[x]+sval[bel[p]];
if (!vis[p])
{
vis[p]=1;
q.push(p);
}
}
}
}
} void spfa1(int s)
{
memset(disn,0,sizeof(disn));
memset(vis,0,sizeof(vis));
vis[s]=1;
disn[s]=sval[bel[s]];
q.push(s);
while (!q.empty()){
int x = q.front();
q.pop();
vis[x]=0;
for (int i=point[x];i;i=nxt[i])
{
int p = to[i];
if (disn[p]<disn[x]+sval[bel[p]])
{
disn[p]=disn[x]+sval[bel[p]];
if (!vis[p])
{
vis[p]=1;
q.push(p);
}
}
}
}
} int main()
{
n=read(),m=read();
for (int i=1;i<=m;i++) {
x[i]=read(),y[i]=read();
addedge(x[i],y[i]);
}
for (int i=1;i<=n;i++)
{
if (!dfn[i]) tarjan(i);
}
//for (int i=1;i<=n;i++) cout<<sval[i]<<endl;
memset(point,0,sizeof(point));
cnt=0;
for (int i=1;i<=m;i++)
{
if (bel[x[i]]!=bel[y[i]])
{
addedge(roo[x[i]],roo[y[i]]);
num[i]=1;
}
}
spfa(roo[1]);
memset(point,0,sizeof(point));
cnt=0;
for (int i=1;i<=m;i++)
{
if (num[i]) addedge(roo[y[i]],roo[x[i]]);
}
spfa1(roo[1]);
int ans=0;
//for (int i=1;i<=n;i++) cout<<dis[i]<<" "<<disn[i]<<endl;
for (int i=1;i<=m;i++)
{
if (!num[i]) continue;
if (dis[roo[y[i]]] && disn[roo[x[i]]])
ans=max(ans,dis[roo[y[i]]]+disn[roo[x[i]]]-sval[bel[roo[1]]]);
}
cout<<ans;
return 0;
}

洛谷3119 草鉴定(tarjan)的更多相关文章

  1. 洛谷P3119草鉴定

    题目 草鉴定,tarjan可以用来缩点,优化spfa的时间, 缩点之后就是一个\(DAG\)了,因此完全可以用来跑spfa上的最长路,然后枚举每条边,查看是否这条边的两个节点分别可以到达起点所在的强连 ...

  2. 洛谷P3119 草鉴定

    这个题调了一天.. 传送门 读完题目之后我们不难想出这个题是个tarjan缩点问题,因为尽量多的经过草场,所以一号点所在的强连通分量里左右的点都是不需要在进行走逆向边,所能到达的. 然后问题就落在怎么 ...

  3. 洛谷 1262 间谍网络 Tarjan 图论

    洛谷 1262 图论 tarjan 并不感觉把这道题目放在图的遍历中很合适,虽然思路比较简单但是代码还是有点多的,, 将可收买的间谍的cost值设为它的价格,不可购买的设为inf,按照控制关系连图,T ...

  4. 洛谷3119 [USACO15JAN]草鉴定Grass Cownoisseur

    原题链接 显然一个强连通分量里所有草场都可以走到,所以先用\(tarjan\)找强连通并缩点. 对于缩点后的\(DAG\),先复制一张新图出来,然后对于原图中的每条边的终点向新图中该边对应的那条边的起 ...

  5. luogu3119/bzoj3887 草鉴定 (tarjan缩点+spfa)

    首先缩一波点,就变成了一个DAG,边权是出点的大小 那我们走到某个点的时候可能会有两种状态:已经走过反边或者没走过 于是就把一个点拆成两层(x和x+N),第二层的点表示我已经走过反边了,每层中的边和原 ...

  6. Luogu3119 草鉴定-Tarjan+Topsort

    Solution 简单的$Tarjan$题. 有大佬现成博客 就不写了 → 传送门 Code #include<cstdio> #include<cstring> #inclu ...

  7. 洛谷 P3119 [USACO15JAN]草鉴定Grass Cownoisseur 解题报告

    P3119 [USACO15JAN]草鉴定Grass Cownoisseur 题目描述 约翰有\(n\)块草场,编号1到\(n\),这些草场由若干条单行道相连.奶牛贝西是美味牧草的鉴赏家,她想到达尽可 ...

  8. 【洛谷P3119】[USACO15JAN]草鉴定Grass Cownoisseur

    草鉴定Grass Cownoisseur 题目链接 约翰有n块草场,编号1到n,这些草场由若干条单行道相连.奶牛贝西是美味牧草的鉴赏家,她想到达尽可能多的草场去品尝牧草. 贝西总是从1号草场出发,最后 ...

  9. 洛谷——P3119 [USACO15JAN]草鉴定Grass Cownoisseur

    P3119 [USACO15JAN]草鉴定Grass Cownoisseur 题目描述 In an effort to better manage the grazing patterns of hi ...

随机推荐

  1. redis subscribe/publish(发布订阅)

    redis的发布端 package dubbo.wangbiao.project.pubsub; import org.apache.commons.pool2.impl.GenericObjectP ...

  2. 二.Go微服务--令牌桶

    1. 令牌桶 1.1 原理 我们以 r/s 的速度向桶内放置令牌,桶的容量为 b , 如果桶满了令牌将会丢弃 当请求到达时,我们向桶内获取令牌,如果令牌足够,我们就通过转发请求 如果桶内的令牌数量不够 ...

  3. opencv入门系列教学(七)改变颜色空间、提取彩色对象

    ​ 0.序言 之前的博客里我们介绍了opencv在图像上的基本操作,下面我们来进行稍微深入一点的介绍,从这里开始我们可以发现opencv库能给我们带来的更多更有趣的功能.从现在开始,我们将逐步深入了解 ...

  4. vscode 1.32.x按下鼠标左键无法拖曳选择,而旧一点的版本1.30.2可以

    最近升级vscode后,无法通过鼠标左键选择文本,恢复到旧版本1.30.2就可以了. 另外:1.32.x和1.31.1都不正常 进一步测试发现:在中文输入法下(无论中英输入模式),都有问题:切换到纯英 ...

  5. javaScript知识储备

    javaScript知识储备 组成 ECMAScript(核心) 提供语法.变量等,遵循ECMA-262标准 DOM(文档对象模型) 提供操作HTML标签的API,遵循W3C规范 BOM(浏览器对象模 ...

  6. go语言调用everything的SDK接口

    介绍 官方SDK地址 本项目会将官方dll编译到可执行程序中,运行时无需考虑dll问题. 根据官方介绍,使用SDK前需要运行everything程序. 执行go build -tag ASCII时编译 ...

  7. 腾讯与Intel就云游戏的探讨

    今天去参加了在腾讯北京总部的腾讯音视频技术 HUB 技术巡回大会,对其中的云游戏应用的探讨格外感兴趣.正巧最近元宇宙概念很火,这篇文章就大会中对云游戏的探讨进行总结和汇报. 讲述一下来自Intel的工 ...

  8. Linux常用命令 - rm命令详解

    21篇测试必备的Linux常用命令,每天敲一篇,每次敲三遍,每月一循环,全都可记住!! https://www.cnblogs.com/poloyy/category/1672457.html 删除/ ...

  9. Golang入门学习(二):控制分支

    文章目录 @[TOC] 1. 控制分支 1.1 if-else分支 1.2 switch分支 1.4 while 和do...while循环结构 1.5 多种循环结构 1.6 break 1.7 co ...

  10. HTTP快速入门

    一.tomcat端口号设置为80,访问时候可以不加:http协议1.1版本可以复用连接,请求结束后会稍微等会: 二. 表单,get方式提交: 三.user-agent告诉服务器是哪个浏览器,代码中解决 ...