题目大意

约翰有\(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. pixhawk入门

    PX4 是软件名称,代码约30万行 Pixhawk是硬件名称 MissionPlanner是地面站名称 常见术语: WP:Way Point 航电 geofence:地理围栏 Rally Point: ...

  2. LeetCode入门指南 之 二分搜索

    上图表示常用的二分查找模板: 第一种是最基础的,查找区间左右都为闭区间,比较后若不等,剩余区间都不会再包含mid:一般在不需要确定目标值的边界时,用此法即可. 第二种查找区间为左闭右开,要确定targ ...

  3. Linux centos7 nginx 的安装

    2021-08-18 1. 环境 # 操作系统[root@test007 /]# uname -aLinux test007 3.10.0-862.el7.x86_64 #1 SMP Fri Apr ...

  4. introduction-to-64-bit-assembly

    introduction-to-64-bit-assembly NASM - The Netwide Assembler x86-64 下函数调用及栈帧原理 汇编语言基本概念简介 mycode

  5. 云原生 AI 前沿:Kubeflow Training Operator 统一云上 AI 训练

    分布式训练与 Kubeflow 当开发者想要讲深度学习的分布式训练搬上 Kubernetes 集群时,首先想到的往往就是 Kubeflow 社区中形形色色的 operators,如 tf-operat ...

  6. QT之ARM平台的移植

      在开发板中运行QT程序的基本条件是具备QT环境,那么QT的移植尤为重要,接下载我将和小伙伴们一起学习QT的移植. 一.准备材料 tslib源码 qt-everywhere-src-5.12.9.t ...

  7. PPP协议、PPPoE协议、L2TP协议的关系

    1. 简述 首先对这3中协议做一个简单的描述: 协议 协议类型 描述 PPP 点对点链路层协议 应用最广泛的点对点协议,可应用在多种网络,改善了SLIP协议的不足 PPPoE 点对点链路层协议 对PP ...

  8. Abp Vnext3 vue-admin-template(一用户登录)

    Git地址https://github.com/PanJiaChen/vue-admin-template/blob/master/README-zh.md 官方文档https://panjiache ...

  9. Tensorflow保存神经网络参数有妙招:Saver和Restore

    摘要:这篇文章将讲解TensorFlow如何保存变量和神经网络参数,通过Saver保存神经网络,再通过Restore调用训练好的神经网络. 本文分享自华为云社区<[Python人工智能] 十一. ...

  10. 判断IE浏览器版本

    //判断IE浏览器版本 function IEVersion() { var userAgent = navigator.userAgent; //取得浏览器的userAgent字符串 var isI ...