1. 程式人生 > >P3627 [APIO2009]搶掠計劃

P3627 [APIO2009]搶掠計劃

sdi color front register reg ++ tdi ret 強連通分量

P3627 [APIO2009]搶掠計劃

Tarjan縮點+最短(最長)路

顯然的縮點......

在縮點時,順便維護每個強連通分量的總權值

縮完點按照慣例建個新圖

然後跑一遍spfa最長路,枚舉每個有酒吧的點即可

(但是我為什麽會搞dp呢.......)

dp:81pts

(這麽顯然的最長路,為什麽會搞dp呢.........)

怕不是被dp題毒害了(大霧)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cctype>
using
namespace std; template <typename T> inline T min(T &a,T &b) {return a<b ?a:b;} template <typename T> inline T max(T &a,T &b) {return a>b ?a:b;} template <typename T> inline void read(T &x){ char c=getchar(); x=0; while(!isdigit(c)) c=getchar();
while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar(); } queue <int> h; const int N=1000002; int n,m,s,p,dfs_clock,dfn[N],low[N],tot,be[N],_top,st[N]; int val1[N],cnt,hd[N],nxt[N],ed[N],poi[N]; int val2[N],cnt2,hd2[N],nxt2[N],ed2[N],poi2[N]; int d[N]; bool bar1[N],bar2[N],vis[N]; inline
void add(int x,int y){ nxt[ed[x]]=++cnt; hd[x]= hd[x] ? hd[x]:cnt; ed[x]=cnt; poi[cnt]=y; } inline void add2(int x,int y){ nxt2[ed2[x]]=++cnt2; hd2[x]= hd2[x] ? hd2[x]:cnt2; ed2[x]=cnt2; poi2[cnt2]=y; } inline void tarjan(int x){ dfn[x]=low[x]=++dfs_clock; st[++_top]=x; for(int i=hd[x];i;i=nxt[i]){ if(!dfn[poi[i]]) tarjan(poi[i]),low[x]=min(low[x],low[poi[i]]); else if(!be[poi[i]]) low[x]=min(low[x],dfn[poi[i]]); } if(dfn[x]==low[x]){ be[x]=++tot; val2[tot]=val1[x]; while(st[_top]!=x) be[st[_top]]=tot,val2[tot]+=val1[st[_top--]]; //維護總權值 --_top; } } int spfa(){ h.push(be[s]); vis[be[s]]=1; while(!h.empty()){ int x=h.front(); h.pop(); vis[x]=0; for(register int i=hd2[x];i;i=nxt2[i]) if(d[x]+val2[x]>d[poi2[i]]){ //最長路 d[poi2[i]]=d[x]+val2[x]; if(!vis[poi2[i]]) h.push(poi2[i]),vis[poi2[i]]=1; } }int ans=0; for(register int i=1;i<=tot;++i) //枚舉有酒吧的強連通分量 if(bar2[i]) ans=max(ans,d[i]+val2[i]); return ans; } int main(){ read(n); read(m); int q1,q2; for(register int i=1;i<=m;++i) read(q1),read(q2),add(q1,q2); for(register int i=1;i<=n;++i) read(val1[i]); read(s); read(p); for(register int i=1;i<=p;++i) read(q1),bar1[q1]=1; for(register int i=1;i<=n;++i) if(!dfn[i]) tarjan(i); for(register int i=1;i<=n;++i){ if(bar1[i]) bar2[be[i]]=1; //給新圖做上是否有酒吧的標記 for(register int j=hd[i];j;j=nxt[j]) if(be[i]!=be[poi[j]]) add2(be[i],be[poi[j]]); }printf("%d",spfa()); return 0; }

P3627 [APIO2009]搶掠計劃