题目

草鉴定,tarjan可以用来缩点,优化spfa的时间,

缩点之后就是一个\(DAG\)了,因此完全可以用来跑spfa上的最长路,然后枚举每条边,查看是否这条边的两个节点分别可以到达起点所在的强连通分量。(因为要返回到1点)。然后更新答案就可以了。

可是为什么要缩点呢,因为只能逆行一次,逆行之后通过在强连通分量上的点可以把强连通分量上的所有点全都遍历一次,最后还可以回到强连通分量上的起点,所以可以tarjan缩点。

#include <bits/stdc++.h>
using namespace std;
int n, m, lin[100010], lne[100100], lf[101000], dfn[100010], low[100100], vis[100100], belong[100100], dis[1001000], dis2[101000], color, tot, cnt, ans, cntne, cntf;
stack <int> s;
int sum[100100];struct edg {
int to, nex;
}e[1000100], f[1000100], ne[100100];
inline void add(int u, int v)
{
e[++cnt].to = v;
e[cnt].nex = lin[u];
lin[u] = cnt;
}
inline void add2(int u, int v)
{
ne[++cntne].to = v;
ne[cntne].nex = lne[u];
lne[u] = cntne;
}
inline void addf(int u, int v)
{
f[++cntf].to = v;
f[cntf].nex = lf[u];
lf[u] = cntf;
}
inline void tarjan(int u)
{
dfn[u] = low[u] = ++tot;
s.push(u); vis[u] = 1;
for(int i = lin[u]; i; i = e[i].nex)
{
int v = e[i].to;
if(!dfn[v]) {
tarjan(v);
low[u] = min(low[u],low[v]);
}
else if(vis[v]) low[u] = min(low[u],dfn[v]);
}
if(low[u] == dfn[u])
{
int v = -3;
color++;
do
{
v = s.top(); s.pop();
belong[v] = color;
vis[v] = 0;
sum[color]++;
} while (u != v);
}
}
int inq[101000];
inline void spfa()
{
memset(dis, -123, sizeof(dis));
queue <int> q;
dis[belong[1]] = sum[belong[1]];
q.push(belong[1]);
while (!q.empty())
{
int cur = q.front(); q.pop(); inq[cur] = 0;
for (int i = lne[cur]; i; i = ne[i].nex)
{
int to = ne[i].to;
if (dis[cur] + sum[to] > dis[to])
{
dis[to] = dis[cur] + sum[to];
if (!inq[to])
inq[to] = 1, q.push(to);
}
}
}
}
inline void sf()
{
memset(dis2, -123, sizeof(dis2));
queue <int> q;
// memset(vis, 0, sizeof(vis));
dis2[belong[1]] = sum[belong[1]]; q.push(belong[1]);
while (!q.empty())
{
int cur = q.front(); q.pop(); inq[cur] = 0;
for (int i = lf[cur]; i; i = f[i].nex)
{
int to = f[i].to;
if(dis2[cur] + sum[to] > dis2[to])
{
dis2[to] = dis2[cur] + sum[to];
if (!inq[to])
inq[to] = 1, q.push(to);
}
}
}
}
int b1[100100], b2[101000];
void dfs1(int u)
{
b1[u] = 1;
for (int i = lne[u]; i; i = ne[i].nex)
if (!b1[ne[i].to])
dfs1(ne[i].to);
}
void dfs2(int u)
{
b2[u] = 1;
for (int i = lf[u]; i; i = f[i].nex)
if (!b2[f[i].to])
dfs2(f[i].to);
}
inline void init()
{
scanf("%d%d", &n, &m);
for (int i = 1, u, v; i <= m; i++)
scanf("%d%d", &u, &v), add(u, v);
for (int i = 1; i <= n; i++)
if (!dfn[i]) tarjan(i); }
inline void jiantu()
{
for (int i = 1; i <= n; i++)
for (int j = lin[i]; j; j = e[j].nex)
{
int to = e[j].to;
if (belong[i] != belong[to]) add2(belong[i], belong[to]), addf(belong[to], belong[i]);
}
}
int main()
{
init();
jiantu();
dfs1(belong[1]);
dfs2(belong[1]);
spfa();
sf();
for (int i = 1; i <= color; i++)
if (b1[i])
for (int j = lf[i]; j; j = f[j].nex)
if (b2[f[j].to])
ans = max(ans, dis2[f[j].to] + dis[i]);
ans -= sum[belong[1]];
printf("%d\n", ans);
return 0;
}

洛谷P3119草鉴定的更多相关文章

  1. 洛谷P3119 草鉴定

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

  2. 洛谷3119 草鉴定(tarjan)

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

  3. 【题解】洛谷P3119 Grass Cownoisseur G

    题面:洛谷P3119 Grass Cownoisseur G 本人最近在熟悉Tarjan的题,刷了几道蓝题后,我飘了 趾高气扬地点开这道紫题,我一瞅: 哎呦!这不是分层图吗? 突然就更飘了~~~ 用时 ...

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

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

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

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

  6. 洛谷 P3119 [USACO15JAN]草鉴定Grass Cownoisseur (SCC缩点,SPFA最长路,枚举反边)

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

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

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

  8. 洛谷P3119 USACO15JAN 草鉴定

    题目描述 In an effort to better manage the grazing patterns of his cows, Farmer John has installed one-w ...

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

    屠龙宝刀点击就送 Tarjan缩点+拓扑排序 以后缩点后建图看n范围用vector ,或者直接用map+vector 结构体里数据要清空 代码: #include <cstring> #i ...

随机推荐

  1. Comet OJ Contest 4

    A:签到. #include<bits/stdc++.h> using namespace std; #define ll long long #define inf 1000000010 ...

  2. [A]System.Web.WebPages.Razor.Configuration.HostSection 无法强制转换为 [B]解决办法

  3. XPATH中text()和string()的使用区别

    <table style="WIDTH: 95.45%; BORDER-COLLAPSE: collapse; EMPTY-CELLS: show; MARGIN-LEFT: 4.55 ...

  4. LunHui 的生命观

    LunHui 的生命观 来源 https://www.zhihu.com/question/346510295 作者:齐天大圣链接:https://www.zhihu.com/question/346 ...

  5. java中的权限修饰符&关键字

    1.类的权限修饰符default(不写权限修饰符),public 说明:类的权限修饰符只有default(不写权限修饰符)和public.   package world default Y N pu ...

  6. centos安装rocketMQ

    1.下载安装包 http://rocketmq.apache.org/release_notes/ 这里选择 4.4.0 版本,点击进去 可以选择源码包或者二进制文件,这里选择二进制文件(ps:如果选 ...

  7. 你听过稀疏数组(sparseArray)吗?

    稀疏数组(sparseArray) 基本介绍 当一个数组中大部分元素为0,或者为同一个值的数组时,可以使用稀疏数组来保存该数组. 稀疏数组的处理方法是: 1.记录数组一共有几行几列,有多少个不同的值 ...

  8. git push error. ! [rejected] master -> master (non-fast-forward)

    错误提示: Cheetah@xxxx MINGW64 /e/Projs/enft/data/cv_key_frame (master) $ git push To github.com:Anthony ...

  9. 【转载】C#将字符串中字母全部转换为大写或者小写

    在C#的编程开发过程中,有时候判断字符串是否相等时,并不关注字母的大小写,此时在C#中可以使用ToUpper方法将字符串中所有的字母转换为大写,使用ToLower方法可以将字符串中所有字母转换为小写. ...

  10. 【转载】Session对象的作用以及常见属性

    Session对象是Asp.Net应用程序中非常重要的一个内置对象,Session是指用户从打开浏览器访问服务器到关闭浏览器之间的会话状态,在一个会话期间,服务器会自动分配一个标识SessionId. ...