[USACO15JAN]草鉴定Grass Cownoisseur,洛谷之提高历练地,强连通分量

正题

      [USACO15JAN]草鉴定Grass Cownoisseur

      这一题好像很烦,因为要处理“反向走一次”这个东西。

      但是我们好像枚举就可以啊~~

      首先要缩点,因为环内的两个节点都可以互相到达。

      缩完点之后,我们就想,怎么才可以满足这个条件。

      其实就是要想,建一条边之后成环嘛.

      那么反转一条边后所形成环的大小就等于1所在连通分块到弧尾(出发点)的最大距离加上弧头(结束点)到1所在连通分块的最大距离。

      我们可以举个例子。。

[USACO15JAN]草鉴定Grass Cownoisseur,洛谷之提高历练地,强连通分量_第1张图片

如上图,我们枚举到i这条边要反转过来,那么所形成环的大小就等于1到y所经过连通分块的大小总和,加上x到1所经过连通分块的大小总和。(因为边被反过来了)

      现在的问题就是怎么求1到其他点的最大距离(距离为连通分块大小总和),和其他点到1的最大距离。

      明显啊~两遍SPFA,一遍从1正向边跑出去,一便从1反向边跑出去(相当于其他点通过正向边跑到1点)

      当然上面说的都是缩点之后的事情哦~DAG

#include
#include
#include
#include
#include
using namespace std;

int n,m;
struct edge{
	int x,y,next;
}s[100010];
struct newedge{
	int x,y,next;
}p[100010];
int first[100010];
int len=0;
struct node{
	int dfn,low;
}op[100010];
int t=0;
stack sta;
bool tf[100010];
int size[100010];
int where[100010];
int dis[2][100010];
int tot=0;

void Tarjan(int x){
	t++;
	op[x].dfn=op[x].low=t;
	sta.push(x);tf[x]=true;
	for(int i=first[x];i!=0;i=s[i].next){
		int y=s[i].y;
		if(op[y].dfn==0){
			Tarjan(y);
			if(op[y].low f;
	f.push(where[1]);
	memset(dis[xx],-1,sizeof(dis[xx]));
	dis[xx][where[1]]=0;
	while(!f.empty()){
		int x=f.front();
		f.pop();
		for(int i=first[x];i;i=p[i].next){
			int y=p[i].y;
			if(dis[xx][y]

你可能感兴趣的:([USACO15JAN]草鉴定Grass Cownoisseur,洛谷之提高历练地,强连通分量)