洛谷P3627 [APIO2009]抢掠计划
考试的时候一看就把大概的思路想出来了,结果tarjan缩点还没看,mmdd
思路:tarjian求强连通分量+缩点连边+SPFA最长路
code如下
#include<bits/stdc++.h>
#define re register int
using namespace std;
int n, m, t, cnt, st, ans, root, s, p, vis[500010], dfn[500010], low[500010], money[500010], wine[500010], belong[500010], d[500010], dis[500010];
vector<int>Edge[500010],edge[500010];
stack<int>stk;
int read()
{
int ans = 0;
char w = ' ', ch = getchar();
while(ch < '0' || ch > '9')
{
w = ch;
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
ans = (ans << 3) + (ans << 1);
ans += ch - '0';
ch = getchar();
}
return (w == '-' ? -ans : ans);
}
void tarjan(int x)
{
dfn[x] = low[x] = ++t;
stk.push(x);
vis[x]=1;
for(re j = 0; j < Edge[x].size(); j++)
{
int y = Edge[x][j];
if(!dfn[y])
{
tarjan(y);
low[x] = min(low[x], low[y]);
}
else if(vis[y])
{
low[x] = min(dfn[y], low[x]);
}
}
if(dfn[x]==low[x])
{
cnt++;
int z=0;
do
{
z=stk.top();
stk.pop();
if(z==s) st=cnt;
vis[z]=0;
belong[z]=cnt;
d[cnt]+=money[z];
}while(z!=x);
}
}
void SPFA(int x)
{
queue<int>q;
memset(vis,0,sizeof(vis));
memset(dis,-1,sizeof(dis));
q.push(x);
vis[x]=1;
dis[x]=d[x];
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=0;
for(re j=0;j<edge[u].size();j++)
{
int v=edge[u][j];
if(dis[v]<dis[u]+d[v])
{
dis[v]=dis[u]+d[v];
if(!vis[v])
{
vis[v]=1;
q.push(v);
}
}
}
}
}
int main()
{
//freopen("atm.in","r",stdin);
//freopen("atm.out","w",stdout);
int a1, a2;
n=read();m=read();
for(re i = 1; i <= m; i++)
{
a1 = read();
a2 = read();
Edge[a1].push_back(a2);
}
for(re i=1;i<=n;i++)
{
money[i]=read();
}
s=read();p=read();
for(re i=1;i<=p;i++)
{
wine[i]=read();
}
for(re i=1;i<=n;i++)
{
if(!dfn[i])
{
tarjan(i);
}
}
for(re i=1;i<=n;i++)
{
for(re j=0;j<Edge[i].size();j++)
{
if(belong[i]!=belong[Edge[i][j]])
{
edge[belong[i]].push_back(belong[Edge[i][j]]);
}
}
}
SPFA(st);
for(re i=1;i<=p;i++)
{
ans=max(ans,dis[belong[wine[i]]]);
}
cout<<ans;
return 0;
}