首页 > 其他分享 >P3119 [USACO15JAN] Grass Cownoisseur G 题解

P3119 [USACO15JAN] Grass Cownoisseur G 题解

时间:2023-10-19 17:11:07浏览次数:38  
标签:int 题解 sum edge low Grass col Cownoisseur dis

分析

大概是强连通分量里面最水的一道紫题,不过细节挺多的,做题的时候给蒟蒻震惊到了。

题目要求是从 \(1\) 走到某个点,然后再走回 \(1\) 号点,中途可逆行一次,问最多能经过几个点。

有一个明显的思路是存两个图,一个正图一个反图,正图是为了求 \(1\) 到各个点的距离,反图是为了求各个点到 \(1\) 的距离。

这时考虑逆行,逆行就是将一条边反过来走,反图的作用又体现了。可以枚举点 \(u\),此时在反图枚举 \(v\),因为在正图中看,反图就是逆行了,答案很明显,\(ans \gets \max(dis_{1,~u} + dis_{2,~v} - sum_{col_1})\)。

这里 \(dis_{1,~k}\) 为点 \(1\) 到点 \(k\) 的距离,\(dis_{2,~k}\) 为点 \(k\) 到点 \(1\) 的距离, \(col_k\) 为 \(k\) 点所在强连通分量编号,\(sum_k\) 为编号为 \(k\) 的强连通分量中的点的个数

Accpted Code

/*Co de By Manipula*/
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
struct Edge{
	int v, nxt;
}edge[3][N];
stack<int> st;
int head[3][N], dfn[N], low[N], col[N], sum[N], dis[3][N], vis[3][N];
int num[3], n, m, indx, scc, ans;
void add(int k, int u, int v){edge[k][++num[k]] = (Edge){v, head[k][u]}; head[k][u] = num[k];}
void Tarjan(int u)
{
	dfn[u] = low[u] = ++indx; st.push(u);
	for (int i = head[0][u]; i; i = edge[0][i].nxt)
	{
		int v = edge[0][i].v;
		if (!dfn[v]){Tarjan(v); low[u] = min(low[u], low[v]);}
		else if (!col[v])low[u] = min(low[u], dfn[v]);
	}
	if (dfn[u] == low[u])
	{
		sum[col[u] = ++scc] = 1;
		int x;
		while (x = st.top(), st.pop(), x != u){col[x] = scc; sum[scc]++;}
	}
}
void spfa(int k)
{
	queue<int> q;
	q.push(col[1]);
	dis[k][col[1]] = sum[col[1]];
	vis[k][col[1]] = 1;
	while (!q.empty())
	{
		int u = q.front(); q.pop();
		vis[k][u] = 0;
		for (int i = head[k][u]; i; i = edge[k][i].nxt)
		{
			int v = edge[k][i].v;
			if (dis[k][v] >= dis[k][u] + sum[v])continue;
			dis[k][v] = dis[k][u] + sum[v];
			if (!vis[k][v])q.push(v);
			vis[k][v] = 1;
		}
	}
}
int main()
{
    memset(dis, 0, sizeof(dis));
	cin >> n >> m;
	for (int i = 1; i <= m; i++)
	{
		int u, v; cin >> u >> v;
		add(0, u, v);
	}
	for (int i = 1; i <= n; i++)if (!dfn[i])Tarjan(i);
	for (int u = 1; u <= n; u++)
		for (int i = head[0][u]; i; i = edge[0][i].nxt)
		{
			int v = edge[0][i].v;
			if (col[u] != col[v])add(1, col[u], col[v]), add(2, col[v], col[u]);
		}
	spfa(1); spfa(2);
	ans = sum[col[1]];
	for (int u = 1; u <= scc; u++)
		for (int i = head[2][u]; i; i = edge[2][i].nxt)
		{
			int v = edge[2][i].v;
			if (dis[1][u] && dis[2][v])
				ans = max(ans, dis[1][u] + dis[2][v] - sum[col[1]]);
		}
	cout << ans;
	return 0;
}

另外,上面这份代码是可以被hack数据卡掉的,所以可以想一想优化方法。

标签:int,题解,sum,edge,low,Grass,col,Cownoisseur,dis
From: https://www.cnblogs.com/Manipula/p/17775165.html

相关文章

  • LuoguCF362B Petya and Staircases 题解
    分析简单排序题。首先Petya可以通过跨过一个台阶和两个台阶保证不经过脏台阶,但是不可以通过跨过三个台阶来保证不经过脏台阶,所以只要看有没有连续的三个脏台阶即可。同时,如果第一个台阶和最后一个台阶至少一个是脏台阶那么就不可以达成。AcceptedCode/*CodeByManipula*/......
  • CF424C的题解
    简单题。CF评分才*1600。可以直接先把\(Q\)拆成两部分。\[\begin{aligned}\largea&=\oplus^n_{i=1}p_i\\\largeb&=\oplus^n_{i=1}\oplus^n_{j=1}\\\(i\bmodj)\\\largeQ&=a\oplusb\end{aligned}\]\(a\)很好算,我们看一下\(b\)具体要怎么算。把\(b\)......
  • CF580B的题解
    见到有单调性、有限制的区间问题,很自然地就会想到用尺取去做。先按工资升序排序,然后套上尺取就行了。不会尺取的可以根据这道题去学。时间复杂度\(O(n\logn)\)。#include<cstdio>#include<algorithm>#definelllonglongusingnamespacestd;constintN=1e5+10;intn......
  • ARC166B题解
    发现还没有和我一样的做法。觉得B比A好想的多。令\(A_i\)为\(a_i\)变成\(A\)的倍数最少次数,\(B_i,C_i,AB_i,AC_i,BC_i,ABC_i\)同理。那么我们就有\(A_i=(A-A\bmod{a_i})\bmodA\),其他同理。这一大坨东西显然都能在\(O(n)\)的时间复杂度内算出来。剩下的就很好......
  • [题解]CF1881G Anya and the Mysterious String
    思路发现如果一个字符串中有长度大于等于\(2\)回文子串,必定有长度为\(2\)的回文子串或长度为\(3\)的回文子串,并且形如:aa和aba。所以考虑用线段树这两种情况。维护一段区间的最左、次左、最右、次右的元素,同时用两个标记变量\(f_1,f_2\)分别表示这个区间中是否出现形如......
  • [AGC020F] Arcs on a Circle 题解
    ArcsonaCircle首先,一个非常自然的想法是尝试断环成链。怎么断呢?我们发现,选择最长线段的起点处截断是个非常好的选择,因为不可能有一个线段完全覆盖它。这之后,一个紧接着的想法就是DP。假如把描述中的全部“实点”改成“整点”的话,那么这题是比较trivial的,可以通过随便状压......
  • 洛谷 P4749 [CERC2017] Kitchen Knobs 题解
    KitchenKnobs首先,一个trivial的想法是,因为每个旋钮如果上面的数字并非全部相同则其必有唯一最优位置,故直接扔掉那些全部相同的旋钮,对于剩余的求出其最优位置。明显此位置是一\(0\sim6\)的数。因为是区间同时旋转,所以转成数之后就是区间加同一个数。一个经典套路是差分。这......
  • [ABC207F] Tree Patrolling 题解
    [ABC207F]TreePatrolling弱智DP题,设\(f(i,j,0/1/2)\)表示在点\(i\),子树中有\(j\)个点被覆盖,且\(i\)点自身状态是未被覆盖/被自身覆盖/被某个儿子覆盖,然后树上背包更新就行了。代码:#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongconstintmo......
  • CF1542E2 Abnormal Permutation Pairs (hard version) 题解
    AbnormalPermutationPairs(hardversion)两个限制:字典序小、逆序对大,一个显然的想法就是确保一对关系,统计另一对关系。确保哪一对呢?我们想了想,决定确保字典序小,因为字典序是可以贪心的。具体而言,我们考虑两个排列自第\(i\)位开始出现了不同。这样子,我们便将两个排列各自划......
  • AT_tdpc_tree 木 题解
    木弱智DP题,直接设\(f_i\)表示\(i\)子树内染色的方案数,然后每次合并一个点与它的儿子即可(具体而言,因为儿子间独立,所以方案数就是二项式系数)。需要注意的是因为第一条边可以在任意位置,所以要以每个点为根各DP一次。但是这样每条边会被算两次,所以乘以2的逆元即可。时间......