【BZOJ】1179: [Apio2009]Atm(tarjan+spfa)
3867 ワード
http://www.lydsy.com/JudgeOnline/problem.php?id=1179
縮点建図..
Description
Input
第1行は、2つの整数N、Mを含む.Nは交差点の個数を表し、Mは道路の本数を表す.次のM行は、各行の2つの整数であり、この2つの整数はいずれも1からNの間にあり、i+1行目の2つの整数は、i番目の道路の始点と終点の交差点番号を表す.次のN行は、1行に1つの整数で、交差点ごとのATMのお金の数を順番に表します.次の行には2つの整数S、Pが含まれており、Sは都心の番号、つまり出発の交差点を表しています.Pはバーの数を表す.次の行にはP個の整数があり、P個のバーのある交差点の番号を表しています.
Output
Banditjiが都心からあるバーで強盗が終わるまでの現金の総数を示す整数を出力します.
Sample Input
6 7
1 2
2 3
3 5
2 4
4 1
2 6
6 5
10
12
8
16
1 5
1 4
4
3
5
6
Sample Output
47
HINT
50%の入力保証N,M<=3000.すべての入力保証N,M<=500000.ATMごとに取れる金額は非負の整数で4000を超えない.データを入力すると、都心からSiruseriの一方向の道路に沿って少なくとも1つのバーに着くことができます.
ソurce
縮点建図..
#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
#define rep(i, n) for(int i=0; i<(n); ++i)
#define for1(i,a,n) for(int i=(a);i<=(n);++i)
#define for2(i,a,n) for(int i=(a);i<(n);++i)
#define for3(i,a,n) for(int i=(a);i>=(n);--i)
#define for4(i,a,n) for(int i=(a);i>(n);--i)
#define CC(i,a) memset(i,a,sizeof(i))
#define read(a) a=getint()
#define print(a) printf("%d", a)
#define dbg(x) cout << (#x) << " = " << (x) << endl
#define error(x) (!(x)?puts("error"):0)
#define rdm(x, i) for(int i=ihead[x]; i; i=e[i].next)
inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; }
const int N=1000005, oo=~0u>>1;
int FF[N], LL[N], scc, p[N], vis[N], s[N], top, tot, d[N];
struct GR {
int ihead[N], cnt, n, w[N];
struct dat { int to, next; }e[N];
void add(int u, int v) {
e[++cnt].next=ihead[u]; ihead[u]=cnt; e[cnt].to=v;
}
void tarjan(int x) {
FF[x]=LL[x]=++tot; vis[x]=1; s[++top]=x;
int y;
rdm(x, i) {
y=e[i].to;
if(!FF[y]) tarjan(y), LL[x]=min(LL[x], LL[y]);
else if(vis[y]) LL[x]=min(LL[x], FF[y]);
}
if(LL[x]==FF[x]) {
++scc;
do {
y=s[top--];
vis[y]=0;
p[y]=scc;
} while(x!=y);
}
}
void tarjan() { for1(i, 1, n) if(!FF[i]) tarjan(i); }
void spfa(int x) {
for1(i, 1, n) d[i]=-oo, vis[i]=0;
d[x]=w[x]; vis[x]=1;
int front, tail; front=tail=0;
int *q=s;
q[tail++]=x;
while(front!=tail) {
int u=q[front++], v; if(front==N) front=0; vis[u]=0;
rdm(u, i) if(d[e[i].to]<d[u]+w[e[i].to]) {
v=e[i].to;
d[v]=d[u]+w[v];
if(!vis[v]) {
vis[v]=1;
if(d[q[front]]<d[v]) {
--front; if(front<0) front+=N;
q[front]=v;
}
else {
q[tail++]=v; if(tail==N) tail=0;
}
}
}
}
}
}G, g;
void build() {
G.tarjan();
g.n=scc;
for1(i, 1, G.n) g.w[p[i]]+=G.w[i];
for1(x, 1, G.n) for(int i=G.ihead[x]; i; i=G.e[i].next) if(p[x]!=p[G.e[i].to]) g.add(p[x], p[G.e[i].to]);
}
int n, m, ans, num, bar[N];
int main() {
read(n); read(m); G.n=n;
for1(i, 1, m) { int u=getint(), v=getint(); G.add(u, v); }
for1(i, 1, n) read(G.w[i]);
int s=getint(); read(num);
build();
g.spfa(p[s]);
for1(i, 1, num) read(bar[i]);
for1(i, 1, num) ans=max(ans, d[p[bar[i]]]);
printf("%d
", ans);
return 0;
}
Description
Input
第1行は、2つの整数N、Mを含む.Nは交差点の個数を表し、Mは道路の本数を表す.次のM行は、各行の2つの整数であり、この2つの整数はいずれも1からNの間にあり、i+1行目の2つの整数は、i番目の道路の始点と終点の交差点番号を表す.次のN行は、1行に1つの整数で、交差点ごとのATMのお金の数を順番に表します.次の行には2つの整数S、Pが含まれており、Sは都心の番号、つまり出発の交差点を表しています.Pはバーの数を表す.次の行にはP個の整数があり、P個のバーのある交差点の番号を表しています.
Output
Banditjiが都心からあるバーで強盗が終わるまでの現金の総数を示す整数を出力します.
Sample Input
6 7
1 2
2 3
3 5
2 4
4 1
2 6
6 5
10
12
8
16
1 5
1 4
4
3
5
6
Sample Output
47
HINT
50%の入力保証N,M<=3000.すべての入力保証N,M<=500000.ATMごとに取れる金額は非負の整数で4000を超えない.データを入力すると、都心からSiruseriの一方向の道路に沿って少なくとも1つのバーに着くことができます.
ソurce