Grass Cownoisseur 题解

原题

写一个非常符合直觉的做法,这题肯定要强联通分量缩点,缩完点之后呢?我们发现逆向边只有一条,这启示我们可以通过分层图的方法来解决这个题目。同层连正边,异层连反边即可,边权是每个联通分量的大小。跑一遍 dij 即可。时间复杂度应该是 O(nlogm) 的,代码实现很简单。

#include<bits/stdc++.h> #define pii pair<int,int> using namespace std; const int N=1e5+5; int n,vis[N],dfn[N],low[N],st[N],top,sc,id[N],cnt,mark[N],siz[N],f[N],res[N],m; int dis[N][2],ans; vector<int>e[N],g[N]; struct node { int v,w,fl; bool operator <(const node &a)const { return w>a.w; } }; vector<node>h[N][2]; pii b[N]; void tarjan(int u) { vis[u]=1; dfn[u]=low[u]=++cnt; st[++top]=u,mark[u]=1; for(int p:e[u]) { if(!dfn[p])tarjan(p),low[u]=min(low[u],low[p]); else if(mark[p])low[u]=min(low[u],dfn[p]); } if(dfn[u]==low[u]) { ++sc; int y; do { y=st[top--],siz[sc]++; id[y]=sc,mark[y]=0; g[sc].push_back(y); } while(u!=y); } } signed main() { scanf("%d%d",&n,&m); for(int i=1,x,y; i<=m; i++) { scanf("%d%d",&x,&y); e[x].push_back(y); b[i]= {x,y}; } for(int i=1; i<=n; i++) if(!vis[i])tarjan(i); for(int i=1; i<=m; i++) { if(id[b[i].first]==id[b[i].second ])continue; h[id[b[i].first]][0].push_back({id[b[i].second],siz[id[b[i].second]],0}); h[id[b[i].first]][1].push_back({id[b[i].second],siz[id[b[i].second]],1}); h[id[b[i].second]][0].push_back({id[b[i].first],siz[id[b[i].first]],1}); } memset(dis,-0x3f,sizeof dis); dis[id[1]][0]=0; priority_queue<node>q; q.push({id[1],dis[id[1]][0],0}); while(!q.empty()) { int x=q.top().v,d=q.top().w,fl=q.top().fl; q.pop(); if(d!=dis[x][fl])continue; for(auto tmp:h[x][fl]) { int v=tmp.v ,w=tmp.w,fl1=tmp.fl; if(dis[v][fl1]<dis[x][fl]+w) { dis[v][fl1]=dis[x][fl]+w; q.push({v,dis[v][fl1],fl1}); if(v==id[1]) { ans=max(ans,dis[v][fl1]); } } } } cout<<ans<<endl; return 0; }

__EOF__

本文作者火牛
本文链接https://www.cnblogs.com/hnczy/p/18729204.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   hnczy  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示