[USACO15JAN]草鉴定Grass Cownoisseur
【题目描述】:
[USACO15JAN]草鉴定Grass Cownoisseur
【思路】:
首先我们先思考贝茜不走那条反边,那么对于任意强连通分量\(E\)易知:
- \(\forall u,v \in E\),\(\exists u \to v \ and \ v \to u\)
\(\because\)贝茜每次经过一个草场时只会吃一次草,\(\therefore\)可以进行缩点,缩点后得到一个\(DAG\),统计每一个强连通分量的\(size\)值,表示此强连通分量中有多少个点,然后在\(DAG\)上跑\(DP\)即可。
但是这道题贝茜玩蛇皮,她还可以逆行一次。
所以我们应该换一个思路,缩完点后,考虑到逆行的情况,我们可以把图正反都建一次,设1号点所在的强连通分量为\(E\),求出\(dis1[]\) 和 \(dis2[]\),分别表示以\(E\)为起点和以\(E\)为中点的最长路,然后枚举每一个\(i\),那么答案就是:
- \(max \{ dis1[i] +dis2[v] - size[E]\}\)。
这就相当于走了那条反边。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define inf 0x3f3f3f3f
using namespace std;
int n,m;
const int MAXN = 100005;
struct edge{
int u,v,nxt;
}e[MAXN];int head[MAXN];int cnt = 0;int dfn[MAXN];int low[MAXN];int id = 0;int s[MAXN];int tot = 0;int Bcnt = 0;
int x[MAXN];int y[MAXN];bool vis[MAXN];int size[MAXN];int b[MAXN];bool back[MAXN];int dis1[MAXN];int dis2[MAXN];int ans = -inf;
inline void add(int u,int v){
e[++cnt].u = u;e[cnt].v = v;e[cnt].nxt = head[u];head[u] = cnt;
}
inline void tarjan(int u){
low[u] = dfn[u] = ++id;
s[++tot]=u;vis[u] = 1;
for(int i=head[u];i;i=e[i].nxt){
int v = e[i].v;
if(!dfn[v]){
tarjan(v);
low[u] = min(low[u] , low[v]);
}
else if(vis[v]) low[u] = min(low[u] , dfn[v]);
}
if(dfn[u] == low[u]){
int j=0;Bcnt++;
while(j ^ u){
j = s[tot--];
vis[j] = 0;
b[j] = Bcnt;
size[Bcnt]++;
}
}
}
inline bool cmp(int a,int b){
return a > b;
}
queue<int>q;
inline void dp(int *dis){
memset(dis,0,sizeof dis);
memset(vis,0,sizeof vis);
dis[b[1]] = size[b[1]];
q.push(b[1]);
while(!q.empty()){
int u = q.front();q.pop();vis[u] = 0;
for(int i=head[u];i;i=e[i].nxt){
int v = e[i].v;
if(dis[v] < dis[u] + size[v]){
dis[v] = dis[u] + size[v];
if(!vis[v]){
q.push(v);
vis[v] = 1;
}
}
}
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i){
int u,v;scanf("%d%d",&u,&v);
add(u,v);
x[i] = u;y[i] = v;
}
for(int i=1;i<=n;++i){
if(!dfn[i]){
tarjan(i);
}
}
memset(head,0,sizeof head);cnt = 0;
for(int i=1;i<=m;++i){
if(b[x[i]] ^ b[y[i]]){
add(b[x[i]] , b[y[i]]);
}
}
for(int i=head[b[1]];i;i=e[i].nxt){
int v = e[i].v;
back[v] = 1;
}
dp(dis1);
memset(head,0,sizeof head);cnt = 0;
memset(back,0,sizeof back);
for(int i=1;i<=m;++i){
if(b[x[i]] ^ b[y[i]]){
add(b[y[i]] , b[x[i]]);
}
}
for(int i=head[b[1]];i;i=e[i].nxt){
int v = e[i].v;
back[v] = 1;
}
dp(dis2);
for(int i=1;i<=Bcnt;++i){
if(!dis1[i]) continue;
for(int j=head[i];j;j=e[j].nxt){
int v = e[j].v;
if(!dis2[v]) continue;
ans = max(ans , (dis1[i] + dis2[v] - size[b[1]]));
}
}
printf("%d",ans);
return 0;
}