• 【洛谷3119】[USACO15JAN] Grass Cownoisseur G(Tarjan+SPFA)


    点此看题面

    • 给定一张(n)个点(m)条边的有向图。
    • (1)号点出发走回(1)号点,可以走至多一次反向边,问最多能经过多少节点。
    • (n,mle10^5)

    (Tarjan)

    不考虑可以走反向边这一条件,那么答案就是(1)号点所在强连通分量的点数。

    众所周知强连通分量可以用(Tarjan)

    其实也正是为了复习(Tarjan)我才会来打这道题的。。。

    总而言之,我们先对整张图跑遍(Tarjan)缩一次点。

    走反向边

    考虑走反向边,必然是从(1)号点所在强连通分量向下走到某一个点,然后走反向边回到(1)号点之前的一个点,再走回到(1)号点所在的强连通分量。

    我们枚举反向边((x,y)),令(u_i)(1)号点到其后面每个点的最长路,(v_i)(1)号点到其前面每个点的最长路,那么答案就是最大的(Sz_{c_1}+u_x+v_y)

    想了半天不太清楚怎么从(DAG)中间开始拓扑。。。

    于是只好暴力地写了个(SPFA)求最长路了。

    代码:(O(SPFA))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 100000
    #define Gmax(x,y) (x<(y)&&(x=(y)))
    #define Gmin(x,y) (x>(y)&&(x=(y)))
    using namespace std;
    int n,m;
    struct Graph
    {
    	int ee,lnk[N+5];struct edge {int to,nxt;}e[N+5];
    	I void add(CI x,CI y) {e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y;}
    	I int operator [] (CI x) Con {return lnk[x];}
    	I edge operator () (CI x) Con {return e[x];}
    }G,nG,iG;
    namespace Tarjan//Tarjan缩点
    {
    	int d,dfn[N+5],low[N+5],T,S[N+5],IS[N+5],cnt,c[N+5],Sz[N+5];
    	I void dfs(CI x)
    	{
    		dfn[x]=low[x]=++d,IS[S[++T]=x]=1;for(RI i=G[x];i;i=G(i).nxt) dfn[G(i).to]?
    			IS[G(i).to]&&Gmin(low[x],dfn[G(i).to]):(dfs(G(i).to),Gmin(low[x],low[G(i).to]));
    		if(dfn[x]==low[x]) {++cnt;W(++Sz[c[S[T]]=cnt],IS[S[T]]=0,S[T--]^x);}
    	}
    }
    namespace SPFA//SPFA求最长路
    {
    	int IQ[N+5];queue<int> q;
    	int u[N+5],v[N+5];I void Work(Con Graph& G,int* dis,CI x)
    	{
    		RI i,k,y,t;dis[x]=0,q.push(x);W(!q.empty())
    			for(i=G[k=q.front()],q.pop(),IQ[k]=0;i;i=G(i).nxt) y=G(i).to,
    				dis[y]<(t=dis[k]+Tarjan::Sz[y])&&(dis[y]=t,!IQ[y]&&(q.push(y),IQ[y]=1));
    	}
    }
    int main()
    {
    	using namespace Tarjan;using namespace SPFA;
    	RI i,j,x,y;for(scanf("%d%d",&n,&m),i=1;i<=m;++i) scanf("%d%d",&x,&y),G.add(x,y);
    	for(i=1;i<=n;++i) !dfn[i]&&(dfs(i),0);for(i=1;i<=n;++i) for(j=G[i];//建新图
    		j;j=G(j).nxt) c[i]^c[G(j).to]&&(nG.add(c[i],c[G(j).to]),iG.add(c[G(j).to],c[i]),0);
    	memset(u,-1,sizeof(u)),memset(v,-1,sizeof(v)),Work(nG,u,c[1]),Work(iG,v,c[1]);//跑两侧最长路
    	RI t=Sz[c[1]];for(i=1;i<=cnt;++i) if(~u[i])
    		for(j=iG[i];j;j=iG(j).nxt) ~v[iG(j).to]&&Gmax(t,Sz[c[1]]+u[i]+v[iG(j).to]);//枚举反向边统计答案
    	return printf("%d
    ",t),0;
    }
    
  • 相关阅读:
    Proj THUDBFuzz Paper Reading: PMFuzz: Test Case Generation for Persistent Memory Programs
    入围 WF 后训练记
    算法竞赛历程
    2021 多校 杭电 第十场
    2021 多校 杭电 第九场
    2021 多校 牛客 第十场
    2021 多校 牛客 第九场
    2021 多校 杭电 第八场
    2021 多校 杭电 第六场
    2021 多校 杭电 第七场
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu3119.html
Copyright © 2020-2023  润新知