题意:
给个有向图,每个点有个点权,有些点有酒吧。现在求一个人从任意一点出发获得点权的最大和。要求每个点的点权只能获得一次,且路径最后必须在酒吧结束,可以重复经过点和边。n,m≤500000。
题解:
tarjan缩点之后跑spfa,注意不能用dijkstra,因为求正权边的最长路相当于求最短路时有负权边。
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <stack> 5 #include <queue> 6 #define inc(i,j,k) for(int i=j;i<=k;i++) 7 #define maxn 500010 8 #define INF 0x3fffffff 9 using namespace std; 10 11 inline int read(){ 12 char ch=getchar(); int f=1,x=0; 13 while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();} 14 while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar(); 15 return f*x; 16 } 17 struct e{int t,n;}es[2][maxn]; int g[2][maxn],ess[2]; 18 void pe(int f,int t,bool o){es[o][++ess[o]]=(e){t,g[o][f]}; g[o][f]=ess[o];} 19 int v[2][maxn],scc[maxn],tot,n,m,s,p,ans; 20 bool ins[maxn]; int tim,low[maxn],dfn[maxn]; stack<int>st; 21 void tarjan(int x){ 22 ins[x]=1; low[x]=dfn[x]=++tim; st.push(x); 23 for(int i=g[0][x];i;i=es[0][i].n){ 24 if(!dfn[es[0][i].t])tarjan(es[0][i].t),low[x]=min(low[x],low[es[0][i].t]); 25 else if(ins[es[0][i].t])low[x]=min(low[x],dfn[es[0][i].t]); 26 } 27 if(low[x]==dfn[x]){ 28 tot++; 29 while(!st.empty()){ 30 int y=st.top(); st.pop(); ins[y]=0; scc[y]=tot; 31 v[1][tot]+=v[0][y]; if(x==y)break; 32 } 33 } 34 } 35 int d[maxn]; bool inq[maxn]; deque<int>q; 36 void spfa(int s){ 37 inc(i,1,tot)d[i]=-1; d[s]=v[1][s]; inq[s]=1; q.push_back(s); 38 while(!q.empty()){ 39 int x=q.front(); q.pop_front(); inq[x]=0; 40 for(int i=g[1][x];i;i=es[1][i].n)if(d[es[1][i].t]<d[x]+v[1][es[1][i].t]){ 41 d[es[1][i].t]=d[x]+v[1][es[1][i].t]; 42 if(!inq[es[1][i].t]){ 43 if(!q.empty()&&d[es[1][i].t]<d[q.front()])q.push_front(es[1][i].t);else q.push_back(es[1][i].t); 44 inq[es[1][i].t]=1; 45 } 46 } 47 } 48 } 49 int main(){ 50 n=read(); m=read(); inc(i,1,m){int x=read(),y=read(); pe(x,y,0);} inc(i,1,n)v[0][i]=read(); 51 s=read(); p=read(); inc(i,1,n)if(!dfn[i])tarjan(i); 52 inc(i,1,n){ 53 for(int j=g[0][i];j;j=es[0][j].n) 54 if(scc[i]!=scc[es[0][j].t])pe(scc[i],scc[es[0][j].t],1); 55 } 56 spfa(scc[s]); inc(i,1,p){int x=read(); if(d[scc[x]]!=-1)ans=max(ans,d[scc[x]]);} 57 printf("%d",ans); return 0; 58 }
20161114