BZOJ 1589 Trick or Treat on the Farm (tarjan缩点,记忆化搜索)[Usaco 2008 Dec Gold]BZOJ计划

Posted 繁凡さん

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 1589 Trick or Treat on the Farm (tarjan缩点,记忆化搜索)[Usaco 2008 Dec Gold]BZOJ计划相关的知识,希望对你有一定的参考价值。

整理的算法模板合集: ACM模板

点我看算法全家桶系列!!!

实际上是一个全新的精炼模板整合计划



Weblink

https://hydro.ac/d/bzoj/p/1589

Problem

每年万圣节,威斯康星的奶牛们都要打扮一番,出门在农场的 n n n 个牛棚里转悠,来采集糖果。她们每走到一个未曾经过的牛棚,就会采集这个棚里的 1 1 1 颗糖果。农场不大,所以约翰要想尽法子让奶牛们得到快乐。

他给每一个牛棚设置了一个「后继牛棚」。牛棚 i i i 的后继牛棚是 x i x_i xi 。他告诉奶牛们,她们到了一个牛棚之后,只要再往后继牛棚走去,就可以搜集到很多糖果。事实上这是一种有点欺骗意味的手段,来节约他的糖果,因为每一只奶牛最多只能在同一个牛棚中采集到的一个糖果。第 i i i 只奶牛从牛棚 i i i 开始她的旅程。请你计算,每一只奶牛可以采集到多少糖果。

1 ≤ n ≤ 1 0 5 1≤n≤10^5 1n105

Solution

狡猾的约翰设计了一个圈套,只要奶牛走到一个环里,就不会再走出去了,而这头奶牛能获得的糖果数量显然就是这个环的 s i z e \\mathrm{size} size

对于给定的这个有向图,每个点只有两种情况:

  • 要么在环中,答案显然是环的 s i z e \\mathrm{size} size
  • 要么通过一条链与环相接,答案显然是点到环的最短距离 + 环的 s i z e \\mathrm{size} size

为了计算点到环的最短距离,我们先对图进行缩点并记录各个环的大小 ,然后对于新图跑一个记忆化搜索统计答案即可,当然直接跑也行()。

Hint

注意特判环大小为 1 1 1 也即自环的情况。

Code

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 6, maxm = maxn << 1 | 7;

int n, m, s, t;
int head[maxn], ver[maxm], edge[maxm], nex[maxn], tot;
bool vis[maxn];
bool ins[maxn];
int dfn[maxn], low[maxn], tim;
int stk[maxn], top;
int scc_cnt, scc_id[maxn], scc_size[maxn];
vector <int> scc[maxn];
int nex_node[maxn];
int ans[maxn];

#define input(x) input(x);
#define print(x) print(x);

template <typename T> inline T input(T &x)
{
	x = 0;
	T f = 0;
	char ch = getchar();
	while(!isdigit(ch)) {f |= (ch == '-'), ch = getchar();}
	while(isdigit(ch)) {x = x * 10 + ch - 48, ch = getchar();}
	if(f) x = -x;
	return x;
}

template <typename T> inline void print(T x)
{
	if(x < 0) putchar('-');
	if(x > 9)
		print(x / 10);
	putchar(x % 10 + 48);
}

void add(int x, int y)
{
	ver[tot] = y;
	nex[tot] = head[x];
	head[x] = tot ++ ;
}

void tarjan(int x)
{
	dfn[x] = ++ tim;
	low[x] = tim;
	ins[x] = true;
	stk[ ++ top] = x;
	for (int i = head[x]; ~i; i = nex[i]) {
		int y = ver[i];
		if(dfn[y] == 0) {
			tarjan(y);
			low[x] = min(low[x], low[y]);
		}
		else if(ins[x])
			low[x] = min(low[x], dfn[y]);
	}
	if(dfn[x] == low[x]) {
		scc_cnt ++ ;
		int y;
		do {
			y = stk[top -- ];
			scc_id[y] = scc_cnt;
			scc_size[scc_cnt] ++ ;
			scc[scc_cnt].emplace_back(y);
		}while(x != y);
	}
}

void dfs(int x, int y, int step)
{
	if(ans[y] != 0) {
		ans[x] = ans[y] + step;
		return ;
	}
	dfs(x, nex_node[y], step + 1);
}


void pre_work()
{
    tot = 0;
	memset(head, -1, sizeof head);
	memset(dfn, 0, sizeof dfn);
	memset(scc_size, 0, sizeof scc_size);
}

int main()
{
    pre_work();
	n = input(n) 
	
	for (int i = 1; i <= n; ++ i) {
		int x; 
 		x = input(x)
		nex_node[i] = x;
		add(i, nex_node[i]);
		if(i == nex_node[i])
			ans[i] = 1;
	}
	
	for (int i = 1; i <= n; ++ i) 
		if(dfn[i] == 0)
			tarjan(i);

	for (int i = 0; i < tot; ++ i) {
		int x = ver[i ^ 1], y = ver[i];
		if(scc_id[x] == scc_id[y]) continue;
		add(scc_id[x], scc_id[y]);
	}
	
	for (int i = 1; i <= n; ++ i) 
		if(scc_size[scc_id[i]] != 1)
			ans[i] = scc_size[scc_id[i]];	
	
	for (int i = 1; i <= n; ++ i) 
		if(ans[i] == 0)
			dfs(i, nex_node[i], 1);
			
	for (int i = 1; i <= n; ++ i) {
		print(ans[i])
		puts("");
	}
	
	return 0;
}

以上是关于BZOJ 1589 Trick or Treat on the Farm (tarjan缩点,记忆化搜索)[Usaco 2008 Dec Gold]BZOJ计划的主要内容,如果未能解决你的问题,请参考以下文章

bzoj1589 [Usaco2008 Dec]Trick or Treat on the Farm 采集糖果

bzoj 1589: [Usaco2008 Dec]Trick or Treat on the Farm 采集糖果

BZOJ 1589 Trick or Treat on the Farm (tarjan缩点,记忆化搜索)[Usaco 2008 Dec Gold]BZOJ计划

BZOJ 1589 Trick or Treat on the Farm (tarjan缩点,记忆化搜索)[Usaco 2008 Dec Gold]BZOJ计划

BZOJ 1589 Trick or Treat on the Farm (tarjan缩点,记忆化搜索)[Usaco 2008 Dec Gold]BZOJ计划

bzoj 1589: [Usaco2008 Dec]Trick or Treat on the Farm 采集糖果tarjan+记忆化搜索