洛谷P3119 [USACO15JAN]Grass Cownoisseur G (tarjan缩点+边反向搭建处理)
题目链接:https://www.luogu.com.cn/problem/P3119
题目大意:给你m组单向边关系,你可以选择返回走一次,但是要保证出发点是1和终点是1,问你最大能到达几个点
题目解法:
首先我们可以通过缩点将一个强连通分量里的所有点变成一个点,并且可以知道缩点以后的图是没有环的,
此时我们记缩点以后以一号点在第start个强连通分量里;
然后用spaf得出以start到其他点(缩点以后的点)的最长路dis1[],然后用反向的路在得到所有点到start
的最长路dis2[],最后我们可以遍历所以路的反向路得到答案;
ans=max(ans,dis1[b]+dis2[a]-sum[start]);
一些细节:
SPFA建边的时候,可以少一步w,这个时候把siz[v]可以看做成w。还有就是建边思想,正向建边+反向建边的配合
AC代码:
#include<bits/stdc++.h> #define ll long long #define rep(i,a,n) for(int i=a;i<=n;i++) #define per(i,n,a) for(int i=n;i>=a;i--) #define endl '\n' #define eps 0.000000001 #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) #define IO ios::sync_with_stdio(false);cin.tie(0); using namespace std; const int INF=0x3f3f3f3f; const ll inf=0x3f3f3f3f3f3f3f3f; const int mod=1e9+7; const int maxn=5e5+5; int tot,head[maxn]; struct E{ int to,next; }edge[maxn<<1]; void add(int u,int v){ edge[tot].to=v; edge[tot].next=head[u]; head[u]=tot++; } int tot1,head1[maxn]; struct E1{ int to,next,w; }edge1[maxn<<1]; void add1(int u,int v){ edge1[tot1].to=v; edge1[tot1].next=head1[u]; head1[u]=tot1++; } int tot2,head2[maxn]; struct E2{ int to,next,w; }edge2[maxn<<1]; void add2(int u,int v){ edge2[tot2].to=v; edge2[tot2].next=head2[u]; head2[u]=tot2++; } int n,m,uu[maxn],vv[maxn]; int dfn[maxn],low[maxn],id[maxn],vis[maxn],cnt,tott; stack<int> s;int siz[maxn]; void tarjan(int x){ dfn[x]=low[x]=++tott; s.push(x);vis[x]=1; for(int i=head[x];i!=-1;i=edge[i].next){ int v=edge[i].to; if(!dfn[v]){ tarjan(v); low[x]=min(low[x],low[v]); } else if(vis[v]){ low[x]=min(low[x],dfn[v]); } } if(low[x]==dfn[x]){ ++cnt; while(1){ int now=s.top();s.pop(); id[now]=cnt; vis[now]=0; siz[cnt]+=1; if(x==now) break; } } } int d1[maxn],inq1[maxn]; void SPFA1(int x){ queue<int> q1; d1[x]=siz[x];q1.push(x);inq1[x]=1; while(!q1.empty()){ int now=q1.front();q1.pop(); inq1[now]=0; for(int i=head1[now];i!=-1;i=edge1[i].next){ int v=edge1[i].to; if(d1[v]<d1[now]+siz[v]){ d1[v]=d1[now]+siz[v]; if(!inq1[v]){ inq1[v]=1;q1.push(v); } } } } } int d2[maxn],inq2[maxn]; void SPFA2(int x){ queue<int> q2; d2[x]=siz[x];q2.push(x);inq2[x]=1; while(!q2.empty()){ int now=q2.front();q2.pop(); inq2[now]=0; for(int i=head2[now];i!=-1;i=edge2[i].next){ int v=edge2[i].to; if(d2[v]<d2[now]+siz[v]){ d2[v]=d2[now]+siz[v]; if(!inq2[v]){ inq2[v]=1;q2.push(v); } } } } } int main(){ mem(head,-1);mem(head1,-1);mem(head2,-1); cin>>n>>m;tott=cnt=0; rep(i,1,m){ cin>>uu[i]>>vv[i]; add(uu[i],vv[i]); } rep(i,1,n){ if(!dfn[i]) tarjan(i); } rep(i,1,m){ if(id[uu[i]]==id[vv[i]]) continue; add1(id[uu[i]],id[vv[i]]); add2(id[vv[i]],id[uu[i]]); } SPFA1(id[1]);SPFA2(id[1]); int ans=siz[id[1]]; rep(i,1,cnt){ if(!d1[i]) continue; for(int j=head2[i];j!=-1;j=edge2[j].next){ int v=edge2[j].to; if(!d2[v]) continue; ans=max(ans,d1[i]+d2[v]-siz[id[1]]); } } cout<<ans<<endl; }
前ICPC算法竞赛退役选手|现摸鱼ing