1. 程式人生 > >[APIO2009]搶掠計劃 tarjan縮點+spfa BZOJ1179

[APIO2009]搶掠計劃 tarjan縮點+spfa BZOJ1179

pop pre 編號 lse 不同 head bubuko getchar() isdigit

題目描述

Siruseri 城中的道路都是單向的。不同的道路由路口連接。按照法律的規定, 在每個路口都設立了一個 Siruseri 銀行的 ATM 取款機。令人奇怪的是,Siruseri 的酒吧也都設在路口,雖然並不是每個路口都設有酒吧。

Banditji 計劃實施 Siruseri 有史以來最驚天動地的 ATM 搶劫。他將從市中心 出發,沿著單向道路行駛,搶劫所有他途徑的 ATM 機,最終他將在一個酒吧慶 祝他的勝利。

使用高超的黑客技術,他獲知了每個 ATM 機中可以掠取的現金數額。他希 望你幫助他計算從市中心出發最後到達某個酒吧時最多能搶劫的現金總數。他可 以經過同一路口或道路任意多次。但只要他搶劫過某個 ATM 機後,該 ATM 機 裏面就不會再有錢了。 例如,假設該城中有 6 個路口,道路的連接情況如下圖所示:

技術分享圖片

市中心在路口 1,由一個入口符號→來標識,那些有酒吧的路口用雙圈來表

示。每個 ATM 機中可取的錢數標在了路口的上方。在這個例子中,Banditji 能搶 劫的現金總數為 47,實施的搶劫路線是:1-2-4-1-2-3-5。

輸入輸出格式

輸入格式:

第一行包含兩個整數 N、M。N 表示路口的個數,M 表示道路條數。接下來 M 行,每行兩個整數,這兩個整數都在 1 到 N 之間,第 i+1 行的兩個整數表示第 i 條道路的起點和終點的路口編號。接下來 N 行,每行一個整數,按順序表示每 個路口處的 ATM 機中的錢數。接下來一行包含兩個整數 S、P,S 表示市中心的 編號,也就是出發的路口。P 表示酒吧數目。接下來的一行中有 P 個整數,表示 P 個有酒吧的路口的編號。

輸出格式:

輸出一個整數,表示 Banditji 從市中心開始到某個酒吧結束所能搶劫的最多 的現金總數。

輸入輸出樣例

輸入樣例#1: 復制
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
輸出樣例#1: 復制
47

說明

50%的輸入保證 N, M<=3000。所有的輸入保證 N, M<=500000。每個 ATM 機中可取的錢數為一個非負整數且不超過 4000。

輸入數據保證你可以從市中心 沿著 Siruseri 的單向的道路到達其中的至少一個酒吧。

技術分享圖片

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<bitset>
#include<ctime>
#include<time.h>
#include<deque>
#include<stack>
#include<functional>
#include<sstream>
//#include<cctype>
//#pragma GCC optimize(2)
using namespace std;
#define maxn 700005
#define inf 0x7fffffff
//#define INF 1e18
#define rdint(x) scanf("%d",&x)
#define rdllt(x) scanf("%lld",&x)
#define rdult(x) scanf("%lu",&x)
#define rdlf(x) scanf("%lf",&x)
#define rdstr(x) scanf("%s",x)
#define mclr(x,a) memset((x),a,sizeof(x))
typedef long long  ll;
typedef unsigned long long ull;
typedef unsigned int U;
#define ms(x) memset((x),0,sizeof(x))
const long long int mod = 1e9 + 7;
#define Mod 1000000000
#define sq(x) (x)*(x)
#define eps 1e-5
typedef pair<int, int> pii;
#define pi acos(-1.0)
//const int N = 1005;
#define REP(i,n) for(int i=0;i<(n);i++)
typedef pair<int, int> pii;

inline int rd() {
	int x = 0;
	char c = getchar();
	bool f = false;
	while (!isdigit(c)) {
		if (c == ‘-‘) f = true;
		c = getchar();
	}
	while (isdigit(c)) {
		x = (x << 1) + (x << 3) + (c ^ 48);
		c = getchar();
	}
	return f ? -x : x;
}


ll gcd(ll a, ll b) {
	return b == 0 ? a : gcd(b, a%b);
}
int sqr(int x) { return x * x; }



/*ll ans;
ll exgcd(ll a, ll b, ll &x, ll &y) {
	if (!b) {
		x = 1; y = 0; return a;
	}
	ans = exgcd(b, a%b, x, y);
	ll t = x; x = y; y = t - a / b * y;
	return ans;
}
*/
int n, m;
int idx;
int col[maxn], val[maxn];
int head[maxn];
int sk[maxn], top;
int dfn[maxn], low[maxn];
int tot;
int vis[maxn];
int sum[maxn];
int num[maxn];
int u[maxn], v[maxn];
int S, P;

struct node {
	int u, v, nxt, w;
}e[maxn<<1];

int cnt;
void add1(int u, int v) {
	e[++cnt].v = v; e[cnt].nxt = head[u]; head[u] = cnt;
}
void add2(int u, int v, int w) {
	e[++cnt].v = v; e[cnt].u = u; e[cnt].w = w;
	e[cnt].nxt = head[u]; head[u] = cnt;
}

void tarjan(int x) {
	sk[++top] = x; vis[x] = 1; low[x] = dfn[x] = ++idx;
	for (int i = head[x]; i; i = e[i].nxt) {
		int v = e[i].v;
		if (!dfn[v]) {
			tarjan(v); low[x] = min(low[x], low[v]);
		}
		else if (vis[v]) {
			low[x] = min(low[x], dfn[v]);
		}
	}
	if (dfn[x] == low[x]) {
		tot++;
		while (sk[top + 1] != x) {
			col[sk[top]] = tot; sum[tot] += val[sk[top]];
			vis[sk[top--]] = 0; num[tot]++;
		}
	}
}
queue<int>q;
//int q[maxn];
int dis[500005];
void spfa() {
	mclr(dis, 0x3f);
	int st = col[S];
	dis[st] = -sum[st];
	q.push(st);
	while (!q.empty()) {
		int tmp = q.front(); q.pop();
		vis[tmp] = 0;
		for (int i = head[tmp]; i; i = e[i].nxt) {
			int to = e[i].v;
			if (dis[to] > dis[tmp] + e[i].w) {
				dis[to] = dis[tmp] + e[i].w;
				if (!vis[to]) {
					q.push(to); vis[to] = 1;
				}
			}
		}
	}
}

int main()
{
//	ios::sync_with_stdio(0);
	n = rd(); m = rd();
	for (int i = 1; i <= m; i++) {
		u[i] = rd(); v[i] = rd();
		add1(u[i], v[i]);
	}
	for (int i = 1; i <= n; i++)rdint(val[i]);// 點權
	// sum[]為縮完點之後的新圖權值
	for (int i = 1; i <= n; i++) {
		if (!dfn[i])tarjan(i);
	}
	ms(head); ms(e); ms(vis);
	cnt = 0;
	for (int i = 1; i <= m; i++) {
		if (col[u[i]] != col[v[i]]) {
			add2(col[u[i]], col[v[i]], -sum[col[v[i]]]);
		}
	}
	S = rd();
	spfa();
	P = rd();
	ll ans = 0;
	for (int i = 1; i <= P; i++) {
		int dx = rd();
		if (ans < -dis[col[dx]])ans = -dis[col[dx]];
	}
	cout << ans << endl;
	return 0;
}

[APIO2009]搶掠計劃 tarjan縮點+spfa BZOJ1179