bzoj 1179 Atm
题目大意:
一个有向图,有些点可以作为终点,每个点有权值,每个点和边可以走很多遍,点走过之后再走点权不会计入分数
从一个点开始,求一个路径使这条路径的分数最大且终点是给定的点之一
输出这个路径长度
思路:
首先tarjan缩点
然后在新图上用spfa跑最长路(开始非常naive以为用dfs就可以
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<cstring> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 #define ll long long 10 #define MAXN 500100 11 #define inf 2139062143 12 using namespace std; 13 inline int read() 14 { 15 int x=0,f=1;char ch=getchar(); 16 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 17 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 18 return x*f; 19 } 20 int n,m,fst[MAXN],nxt[MAXN],to[MAXN],cnt,val[MAXN],bar[MAXN],s,Fst[MAXN],Nxt[MAXN],To[MAXN]; 21 int ans,dfn[MAXN],low[MAXN],vis[MAXN],stp,top,st[MAXN],sum[MAXN],ok[MAXN],scc,bl[MAXN]; 22 int dis[MAXN],q[MAXN],head,tail; 23 void add(int u,int v) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v;} 24 void Add(int u,int v) {Nxt[++cnt]=Fst[u],Fst[u]=cnt,To[cnt]=v;} 25 void tarjan(int x) 26 { 27 dfn[x]=low[x]=++stp,vis[x]=1,st[++top]=x; 28 for(int i=fst[x];i;i=nxt[i]) 29 if(!dfn[to[i]]) {tarjan(to[i]);low[x]=min(low[x],low[to[i]]);} 30 else if(vis[to[i]]) low[x]=min(low[x],dfn[to[i]]); 31 if(low[x]==dfn[x]) 32 { 33 scc++;int now=0; 34 while(now!=x) 35 { 36 now=st[top--],vis[now]=0,sum[scc]+=val[now],bl[now]=scc; 37 if(bar[now]) ok[scc]=1; 38 } 39 } 40 } 41 void build() 42 { 43 cnt=0; 44 for(int i=1;i<=n;i++) 45 for(int j=fst[i];j;j=nxt[j]) 46 if(bl[i]!=bl[to[j]]) Add(bl[i],bl[to[j]]); 47 } 48 void spfa() 49 { 50 s=bl[s],head=tail=1,q[tail]=s,vis[s]=1; 51 while(head<=tail) 52 { 53 int x=q[head++];vis[x]=0; 54 for(int i=Fst[x];i;i=Nxt[i]) 55 if(dis[To[i]]<dis[x]+sum[To[i]]) 56 { 57 dis[To[i]]=dis[x]+sum[To[i]]; 58 if(!vis[To[i]]) {vis[To[i]]=1,q[++tail]=To[i];} 59 } 60 } 61 } 62 int main() 63 { 64 n=read(),m=read();int a,b,t; 65 while(m--) {a=read(),b=read();add(a,b);} 66 for(int i=1;i<=n;i++) val[i]=read(); 67 s=read(),t=read(); 68 for(int i=1;i<=t;i++) bar[read()]=1; 69 for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); 70 build();spfa(); 71 for(int i=1;i<=scc;i++) if(ok[i]) ans=max(ans,dis[i]); 72 printf("%d",ans+sum[s]); 73 }