洛谷3119 草鉴定(tarjan)
题目大意
约翰有\(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)的更多相关文章
- 洛谷P3119草鉴定
题目 草鉴定,tarjan可以用来缩点,优化spfa的时间, 缩点之后就是一个\(DAG\)了,因此完全可以用来跑spfa上的最长路,然后枚举每条边,查看是否这条边的两个节点分别可以到达起点所在的强连 ...
- 洛谷P3119 草鉴定
这个题调了一天.. 传送门 读完题目之后我们不难想出这个题是个tarjan缩点问题,因为尽量多的经过草场,所以一号点所在的强连通分量里左右的点都是不需要在进行走逆向边,所能到达的. 然后问题就落在怎么 ...
- 洛谷 1262 间谍网络 Tarjan 图论
洛谷 1262 图论 tarjan 并不感觉把这道题目放在图的遍历中很合适,虽然思路比较简单但是代码还是有点多的,, 将可收买的间谍的cost值设为它的价格,不可购买的设为inf,按照控制关系连图,T ...
- 洛谷3119 [USACO15JAN]草鉴定Grass Cownoisseur
原题链接 显然一个强连通分量里所有草场都可以走到,所以先用\(tarjan\)找强连通并缩点. 对于缩点后的\(DAG\),先复制一张新图出来,然后对于原图中的每条边的终点向新图中该边对应的那条边的起 ...
- luogu3119/bzoj3887 草鉴定 (tarjan缩点+spfa)
首先缩一波点,就变成了一个DAG,边权是出点的大小 那我们走到某个点的时候可能会有两种状态:已经走过反边或者没走过 于是就把一个点拆成两层(x和x+N),第二层的点表示我已经走过反边了,每层中的边和原 ...
- Luogu3119 草鉴定-Tarjan+Topsort
Solution 简单的$Tarjan$题. 有大佬现成博客 就不写了 → 传送门 Code #include<cstdio> #include<cstring> #inclu ...
- 洛谷 P3119 [USACO15JAN]草鉴定Grass Cownoisseur 解题报告
P3119 [USACO15JAN]草鉴定Grass Cownoisseur 题目描述 约翰有\(n\)块草场,编号1到\(n\),这些草场由若干条单行道相连.奶牛贝西是美味牧草的鉴赏家,她想到达尽可 ...
- 【洛谷P3119】[USACO15JAN]草鉴定Grass Cownoisseur
草鉴定Grass Cownoisseur 题目链接 约翰有n块草场,编号1到n,这些草场由若干条单行道相连.奶牛贝西是美味牧草的鉴赏家,她想到达尽可能多的草场去品尝牧草. 贝西总是从1号草场出发,最后 ...
- 洛谷——P3119 [USACO15JAN]草鉴定Grass Cownoisseur
P3119 [USACO15JAN]草鉴定Grass Cownoisseur 题目描述 In an effort to better manage the grazing patterns of hi ...
随机推荐
- 二.Go微服务--令牌桶
1. 令牌桶 1.1 原理 我们以 r/s 的速度向桶内放置令牌,桶的容量为 b , 如果桶满了令牌将会丢弃 当请求到达时,我们向桶内获取令牌,如果令牌足够,我们就通过转发请求 如果桶内的令牌数量不够 ...
- asp语言中if判断语句的求助
If a < 5 Then Response.Redirect("1.asp")ElseIf a > 5 And a < 8 Then Response. ...
- k8s笔记0528-基于KUBERNETES构建企业容器云手动部署集群记录-4
部署kubelet 1.二进制包准备 将软件包从linux-node1复制到linux-node2中去. [root@linux-node1 ~]# cd /usr/local/src/kuberne ...
- zap高性能日志
摘要 日志在整个工程实践中的重要性不言而喻,在选择日志组件的时候也有多方面的考量.详细.正确和及时的反馈是必不可少的,但是整个性能表现是否也是必要考虑的点呢?在长期的实践中发现有的日志组件对于计算资源 ...
- ---Docker学习随笔---基础管理部分---
docker是什么?提供快速.高效.轻量的微服务平台 1. 背景介绍突破虚拟机对资源占用高.启动时间长.镜像存储大.集群规模小等限制,摆脱操作系统级的隔离级别,实现进程级管理.主要专用名词: chro ...
- Linux新加磁盘并挂载到目录
步骤:1.分区 ----> 2.格式化 ----> 3.挂载 一.查看当前情况 1. 2. 二.磁盘分区 fdisk /dev/sdb 1.输入n,表示添加一个新的分区 2. e ex ...
- 内核软中断之tasklet机制
1. 软中断IRQ简介 软中断(SoftIRQ)是内核提供的一种基于中断的延时机制, Linux内核定义的软中断有以下几种: enum { HI_SOFTIRQ=0, /*高优先级的tasklet*/ ...
- Collections集合工具类和可变参数
Collections常用的API: public static <T> boolean addAll(Collection<? super T> c, T... elemen ...
- AtCoder Regular Contest 069 D - Menagerie 枚举起点 模拟递推
arc069.contest.atcoder.jp/tasks/arc069_b 题意:一堆不明身份的动物排成一圈,身份可能是羊或狼,羊一定说实话,狼一定说假话.大家各自报自己的两边是同类还是不同类, ...
- 查看Win10商店应用更新日期
查看Win10商店应用更新日期 需要用到一个工具--WP Snitch,网址 https://wpsnitch.appspot.com/ 打开网址后他会给出一个示例,比如给出的是 https://ww ...