1. 程式人生 > >BZOJ 1179 APIO2009 ATM Tarjan+堆優化SPFA

BZOJ 1179 APIO2009 ATM Tarjan+堆優化SPFA

題目大意:給定一個有向圖,每個點上有正權,求一條從起點出發到任意終點的路徑,要求路上的點權和最大(一個點權只能被加一次)

首先Tarjan縮點,易知一個強連通分量內任意一個點權拿到就可以拿到強連通分量內所有的點權

然後這個圖就沒有環了,SPFA跑最長路即可

邊數500W,所以要加堆優化

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 500500
using namespace std;
struct edge{
	int x,y;
}edges[M];
struct abcd{
	int to,next;
}table[M<<1];
int head[M],tot;
int n,m,a[M],ans;
int s,k;
int dpt[M],low[M],T,stack[M],top,v[M],belong[M],cnt,cash[M];
int f[M],heap[M],pos[M];
void Push_Up(int t)
{
	while(t>1&&f[heap[t]]>f[heap[t>>1]])
		swap(heap[t],heap[t>>1]),swap(pos[heap[t]],pos[heap[t>>1]]),t>>=1;
}
void Insert(int x)
{
	heap[++top]=x;
	pos[x]=top;
	Push_Up(top);
}
void Pop()
{
	pos[heap[1]]=0;
	heap[1]=heap[top--];
	if(top) pos[heap[1]]=1;
	int t=2;
	while(t<=top)
	{
		if(t<top&&f[heap[t+1]]>f[heap[t]])
			++t;
		if(f[heap[t]]>f[heap[t>>1]])
			swap(heap[t],heap[t>>1]),swap(pos[heap[t]],pos[heap[t>>1]]),t<<=1;
		else
			break;
	}
}
void SPFA()
{
	int i;
	memset(f,0xef,sizeof f);
	f[belong[s]]=cash[belong[s]];
	Insert(belong[s]);
	while(top)
	{
		int x=heap[1];Pop();
		for(i=head[x];i;i=table[i].next)
			if(f[table[i].to]<f[x]+cash[table[i].to])
			{
				f[table[i].to]=f[x]+cash[table[i].to];
				if(!pos[table[i].to])
					Insert(table[i].to);
				else
					Push_Up(pos[table[i].to]);
			}
	}
}
void Add(int x,int y)
{
	table[++tot].to=y;
	table[tot].next=head[x];
	head[x]=tot;
}
void Tarjan(int x)
{
	int i;
	dpt[x]=low[x]=++T;
	stack[++top]=x;
	for(i=head[x];i;i=table[i].next)
	{
		if(v[table[i].to])
			continue;
		if(dpt[table[i].to])
			low[x]=min(low[x],dpt[table[i].to]);
		else
			Tarjan(table[i].to),low[x]=min(low[x],low[table[i].to]);
	}
	if(dpt[x]==low[x])
	{
		int t;
		++cnt;
		do{
			t=stack[top--];
			v[t]=1;
			belong[t]=cnt;
			cash[cnt]+=a[t];
		}while(t!=x);
	}
}
int main()
{
	int i,x,y;
	cin>>n>>m;
	for(i=1;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		edges[i].x=x;
		edges[i].y=y;
		Add(x,y);
	}
	for(i=1;i<=n;i++)
		scanf("%d",&a[i]);
	cin>>s>>k;
	Tarjan(s);
	memset(head,0,sizeof head);tot=0;
	for(i=1;i<=m;i++)
		if(belong[edges[i].x]!=belong[edges[i].y])
			Add(belong[edges[i].x],belong[edges[i].y]);
	SPFA();
	for(i=1;i<=k;i++)
	{
		scanf("%d",&x);
		ans=max(ans,f[belong[x]]);
	}
	cout<<ans<<endl;
}