首页 > 其他分享 >洛谷 P3119 Grass Cownoisseur G

洛谷 P3119 Grass Cownoisseur G

时间:2024-09-04 20:14:02浏览次数:11  
标签:草场 洛谷 int top stk low Grass 贝西 Cownoisseur

洛谷 P3119 Grass Cownoisseur G

题意

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

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

思路

先强连通分量缩点。

因为若一个子图内所有点都能互相到达,全部走一遍一定最优。

缩点考虑如何反转边。

如果不反转边,走出 \(1\) 所在的分量后不可能回来,所以不能走出,答案为 \(1\) 所在的分量大小。

如果反转边,必定是一个不能到达 \(1\) 的点连向能到达 \(1\) 的点,否则要么不满足题意,要么不优。

缩点后建一张正 DAG 和一张反 DAG。

从 \(1\) 开始广搜两遍。

第一遍在反 DAG 上广搜,搜出每个点能否到达 \(1\) 以及到 \(1\) 的最长路。

第二遍在正 DAG 上广搜,搜出到达 \(1\) 的最长路。

第二遍广搜时搜到一个点,枚举它在反 DAG 上的边,看连接的点能否到达 \(1\)。

若能,则更新答案,即两个点的最长路之和。

代码

#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 5;
int n, m, cnt, low[N], dfn[N];
bool instk[N], ok[N];
int stk[N], top, siz[N];
vector <int> E[N], Z[N], F[N];
queue <int> Q; 
int dis[N], ans, sc, scc[N];
void tarjan(int x) {
	low[x] = dfn[x] = ++ cnt;
	stk[++ top] = x; instk[x] = 1;
	for (auto y : E[x]) {
		if (!dfn[y]) {
			tarjan(y);
			low[x] = min(low[x], low[y]);
		} else if (instk[y])
			low[x] = min(low[x], dfn[y]);
	}
	if (low[x] == dfn[x]) {
		sc ++;
		while (top && stk[top] != x) {
			scc[stk[top]] = sc;
			instk[stk[top]] = 0;
			siz[sc] ++;
			top --;
		}
		scc[stk[top]] = sc;
		instk[stk[top]] = 0;
		siz[sc] ++;
		top --;
	}
}
int main() {
	cin >> n >> m;
	for (int i = 1, u, v; i <= m; i ++) {
		cin >> u >> v;
		E[u].push_back(v);
	}
	for (int i = 1; i <= n; i ++) {
		if (dfn[i]) continue;
		tarjan(i);
	}
	for (int i = 1; i <= n; i ++)
		for (auto v : E[i])
			if (scc[i] != scc[v]) {
				Z[scc[i]].push_back(scc[v]);
				F[scc[v]].push_back(scc[i]);
			}
	Q.push(scc[1]); dis[scc[1]] = siz[scc[1]];
	ans = siz[scc[1]];
	while (!Q.empty()) {
		int x = Q.front(); Q.pop();
		ok[x] = 1;
		for (auto v : F[x]) {
			if (dis[v] < dis[x] + siz[v]) {
				dis[v] = dis[x] + siz[v];
				Q.push(v);
			} 
		}
	}
	Q.push(scc[1]);
	while (!Q.empty()) {
		int x = Q.front(); Q.pop();
		for (auto v : F[x]) {
			if (!ok[v]) continue;
			ans = max(ans, dis[x] + dis[v] - siz[scc[1]]);
		}
		for (auto v : Z[x]) {
			if (dis[v] < dis[x] + siz[v]) {
				dis[v] = dis[x] + siz[v];
				Q.push(v);
			}	
		}
	}
	cout << ans << "\n";
	return 0;
}

标签:草场,洛谷,int,top,stk,low,Grass,贝西,Cownoisseur
From: https://www.cnblogs.com/maniubi/p/18397269

相关文章

  • 洛谷 P9912 Zatopljenje
    洛谷P9912Zatopljenje题意给出长度为\(n\)的序列\(a\),有\(q\)次询问。每次给出\(l,r,x\),询问区间\([l,r]\)中有多少段极长的,\(a\)都大于\(x\)的段。思路离线后扫描线。先把询问和\(a\)离散化,然后扫描\(a\)的值。维护序列\(b\),初始全为\(1\)。扫描从\(......
  • 洛谷 P5340 大中锋的游乐场
    洛谷P5340大中锋的游乐场题意给出一张\(n\)个点\(m\)条边的图,每个点有一个点权\(1\)或\(-1\)。给出点\(s,t\),求出\((s,t)\)间满足以下条件的最短路。任意时刻,走过的路径上点权和均\(\in[-k,k]\)。思路分层图最短路。\(dis_{i,j}\)表示走到\(i\),点权和为\(j......
  • 洛谷 P5618 堵塞的交通
    洛谷P5618堵塞的交通题意有一个\(2\timesC\)的网格图,需要维护\(3\)种操作。连接相邻的两个格子。将相邻的两个格子断开连接。询问两个格子是否联通。思路1考虑分块。连边时块内使用并查集维护,块与块之间用数组标记。删边块内的边时暴力重构并查集,块之间的边清零......
  • 洛谷 B3645 数列前缀和 2 题解
    前缀知识:枚举,费马小定理,逆元,线性乘法逆元,线段树(?)。解法1:暴力如题。暴力枚举即可,30分。由于太简单,不给代码。解法2:前缀积+费马小定理+逆元由于涉及静态区间,可以想到前缀积。前缀积公式为\(q_r/q_{l-1}\),除法恰好可以用逆元来算。直接写即可。不会超时,因为时间为\(O(n\logp)\)......
  • 洛谷题单指南-常见优化技巧-P3143 [USACO16OPEN] Diamond Collector S
    原题链接:https://www.luogu.com.cn/problem/P3143题意解读:找到两个不相交的最长连续序列,使得序列最大值和最小值差不超过k,求两个最长的序列长度和。解题思路:先将所有数从小到大排序,记为a[]要找到两个不相交的最长连续序列,可以采用下面技巧:设b[i]表示i之前“差值在k之内的连续......
  • 洛谷题单指南-常见优化技巧-P4653 [CEOI2017] Sure Bet
    原题链接:https://www.luogu.com.cn/problem/P4653题意解读:选中的灯泡中,某一类较少的总权值减去灯泡数量所得到的收益最大值。解题思路:注意,此题关键是:要使得较少的收益最大化1、要最大化,意味着每次应该选择尽可能大权值的灯泡2、要使A、B类中较少的收益最大化,意味着每次应该优......
  • 洛谷题单指南-常见优化技巧-唯一的雪花 Unique Snowflakes
    原题链接:https://www.luogu.com.cn/problem/UVA11572题意解读:本质上是要计算最长连续不重复子序列的长度,典型的双指针应用。解题思路:通过双指针来枚举子序列,右指针指向的元素每次记录元素出现的次数,可以借助hash数组h[]如果枚举到的元素出现次数超过1,则表示左、右指针之间的子......
  • 洛谷题单指南-常见优化技巧-P2216 [HAOI2007] 理想的正方形
    原题链接:https://www.luogu.com.cn/problem/P2216题意解读:在矩阵中找n*n正方形里最大值和最小值差值的最小值。解题思路:1、枚举法直接枚举所有n*n的正方形的位置,然后在遍历求最大值、最小值,复杂度为O(n^4),显然不能通过。2、二维单调队列既然是求正方形范围内的最值,看起来是......
  • 洛谷题单指南-常见优化技巧-P2032 扫描
    原题链接:https://www.luogu.com.cn/problem/P2032题意解读:求滑动窗口内的最大值,典型的单调队列应用。解题思路:单调队列的三部曲:1、去头。已存入的元素个数超过k,则去头。注意队列里存的是元素下标,只需要用当前下标减去队头元素来判断即可。2、去尾。根据单调队列的单调性,如果......
  • 洛谷 P4819 杀人游戏
    洛谷P4819杀人游戏题意有\(n\)个人,他们之中有一个杀手。每个人都有可能是杀手,并且概率相等。你可以询问若干人。若询问的人是杀手,你会被干掉。若询问的人是平民,你会知道他认识的所有人的身份。给出一张有向图表示这\(n\)个人的关系。求出你活着知道杀手是谁的概率。......