思路很乱,写个博客理一理。

缩点 + dp。

首先发现把一个环上的边反向是意义不大的,这样子不但不好算,而且相当于浪费了一次反向的机会。反正一个强连通分量里的点绕一遍都可以走到,所以我们缩点之后把一个强连通分量放在一起处理。

设$st$表示缩点之后$1$所在的点,设$f_{x}$表示从$st$走到$x$的最长链,$g_{x}$表示从$x$走到$st$的最长链,因为把一个$DAG$上的边反向一下并不会走重复的点,那么我们最后枚举一下边$(x, y)$,把它反向,这样子$f_{x} + g_{y} - siz_{st}$就可以成为备选答案,更新$ans$即可。

注意到有可能整个图强连通,所以$ans$应初始化为$siz_{st}$。

考虑一下$f$和$g$怎么求,一种想法是$st$开始的最长路,我们可以在反图和正图上分别跑一遍$spfa$,这样子可以通过,但是我并不清楚在$DAG$上$spfa$的表现是不是稳定的,另一种想法就是$dp$,直接记搜搞一搞,但是直接记搜是错误的,因为有一些点是不可能走到的,所以在$dp$之前要先$dfs$一遍标记出所有的合法点,然后再进行记搜即可。

时间复杂度$O(n)$。

放上写得很丑很长还可能有锅的代码。

你谷的数据是真的水。

Code:

#include <cstdio>
#include <cstring>
#include <vector>
using namespace std; const int N = 1e5 + ; int n, m, tot = , head[N], dfsc = , dfn[N], low[N];
int scc = , f[N], g[N], inx[N], iny[N], top = , sta[N], bel[N], siz[N];
bool vis[N], ok[N];
vector <int> G1[N], G2[N]; struct Edge {
int to, nxt;
} e[N]; inline void add(int from, int to) {
e[++tot].to = to;
e[tot].nxt = head[from];
head[from] = tot;
} inline void read(int &X) {
X = ; char ch = ; int op = ;
for(; ch > '' || ch < ''; ch = getchar())
if(ch == '-') op = -;
for(; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} inline int min(int x, int y) {
return x > y ? y : x;
} void tarjan(int x) {
low[x] = dfn[x] = ++dfsc;
vis[x] = , sta[++top] = x;
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(!dfn[y]) {
tarjan(y);
low[x] = min(low[x], low[y]);
} else if(vis[y])
low[x] = min(low[x], dfn[y]);
} if(low[x] == dfn[x]) {
++scc;
for(; sta[top + ] != x; --top) {
vis[sta[top]] = ;
siz[scc]++;
bel[sta[top]] = scc;
}
}
} inline void chkMax(int &x, int y) {
if(y > x) x = y;
} void dfs1(int x) {
ok[x] = , vis[x] = ;
for(unsigned int i = ; i < G1[x].size(); i++) {
int y = G1[x][i];
dfs1(y);
}
} int dp1(int x) {
if(vis[x]) return f[x];
vis[x] = ;
int res = ;
for(unsigned int i = ; i < G2[x].size(); i++) {
int y = G2[x][i];
if(ok[y]) chkMax(res, dp1(y));
}
f[x] = res + siz[x];
return f[x];
} void dfs2(int x) {
ok[x] = , vis[x] = ;
for(unsigned int i = ; i < G2[x].size(); i++) {
int y = G2[x][i];
dfs2(y);
}
} int dp2(int x) {
if(vis[x]) return g[x];
vis[x] = ;
int res = ;
for(unsigned int i = ; i < G1[x].size(); i++) {
int y = G1[x][i];
if(ok[y]) chkMax(res, dp2(y));
}
g[x] = res + siz[x];
return g[x];
} int main() {
// freopen("testdata.in", "r", stdin); read(n), read(m);
for(int i = ; i <= m; i++) {
read(inx[i]), read(iny[i]);
add(inx[i], iny[i]);
} for(int i = ; i <= n; i++)
if(!dfn[i]) tarjan(i); for(int i = ; i <= m; i++) {
if(bel[inx[i]] == bel[iny[i]]) continue;
G1[bel[inx[i]]].push_back(bel[iny[i]]);
G2[bel[iny[i]]].push_back(bel[inx[i]]);
} memset(vis, , sizeof(vis));
memset(ok, , sizeof(ok));
dfs1(bel[]); memset(vis, , sizeof(vis));
for(int i = ; i <= scc; i++) {
if(ok[i]) dp1(i);
} memset(vis, , sizeof(vis));
memset(ok, , sizeof(ok));
dfs2(bel[]); memset(vis, , sizeof(vis));
for(int i = ; i <= scc; i++) {
if(ok[i]) dp2(i);
} /* for(int i = 1; i <= scc; i++)
printf("%d ", g[i]);
printf("\n");
for(int i = 1; i <= scc; i++)
printf("%d ", f[i]);
printf("\n"); */ int ans = siz[bel[]];
for(int i = ; i <= m; i++) {
int u = bel[iny[i]], v = bel[inx[i]];
if(u == v) continue;
if(f[u] && g[v]) chkMax(ans, f[u] + g[v] - siz[bel[]]);
} printf("%d\n", ans);
return ;
}

Luogu 3119 [USACO15JAN]草鉴定Grass Cownoisseur的更多相关文章

  1. luogu P3119 [USACO15JAN]草鉴定Grass Cownoisseur

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

  2. [Luogu P3119] [USACO15JAN]草鉴定Grass Cownoisseur (缩点+图上DP)

    题面 传送门:https://www.luogu.org/problemnew/show/P3119 Solution 这题显然要先把缩点做了. 然后我们就可以考虑如何处理走反向边的问题. 像我这样的 ...

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

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

  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. [USACO15JAN]草鉴定Grass Cownoisseur(分层图+tarjan)

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

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

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

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

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

  9. 洛谷—— P3119 [USACO15JAN]草鉴定Grass Cownoisseur || BZOJ——T 3887: [Usaco2015 Jan]Grass Cownoisseur

    http://www.lydsy.com/JudgeOnline/problem.php?id=3887|| https://www.luogu.org/problem/show?pid=3119 D ...

随机推荐

  1. XML 可扩展标记语言

    因 为XML实在是太重要了,而且被广泛应用!不论是数据存储,还是其他方面,如配置文件等.XML是一种对独立于任何编程语言的数据进行编码的机制.在数据 交换领域,正在变得非常流行!因为他的基于节点的存储 ...

  2. 在Laravel外独立使用laravel-mongodb

    laravel框架外部使用laravel-mongodb 插件 下载安装方式主要根据github上的参考: https://github.com/jenssegers/laravel-mongodb# ...

  3. Light Probe

    [Light Probe] Light Probes provide a way to capture and use information about light that is passing ...

  4. Frame animation

    [Frame animation] An animation defined in XML that shows a sequence of images in order (like a film) ...

  5. Windows 2012设置允许单个用户连接多个会话的方法

    WINDOWS 2012 服务器默认只允许单个用户连接一个远程桌面会话,如果已有连接登陆,另外的连接再登陆会踢掉之前的连接.如果需要两个远程桌面同时连接 找到:HKEY_LOCAL_MACHINE\S ...

  6. day22 面向对象基础

    1.什么是面向过程 在介绍面向对象之前,要先明确面向过程 在这之前我们所写的任何代码都是面向过程的 什么是面向过程? 是一种编程思想 面对 朝向 在编写代码时,要时刻想着过程这两个字 过程指的是什么? ...

  7. Appium1.6 定位iOS元素和操作元素

    元素定位方式  第一种:通过Appium1.6的Inspector来查看 具体安装方式前面的随笔已经介绍了:http://www.cnblogs.com/meitian/p/7360017.html ...

  8. springboot security 获取当前登录用户名

    System.out.println(((User)SecurityContextHolder.getContext().getAuthentication().getPrincipal()).get ...

  9. Linux 字符设备驱动及一些简单的Linux知识

    一.linux系统将设备分为3类:字符设备.块设备.网络设备 1.字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据.字符设备是面向流的设备,常见 ...

  10. 第十章 优先级队列 (a1)需求与动机