[SPFA 分块建图] BZOJ 4070 [Apio2015]雅加达的摩天楼

最坏情况有n^2条边,一般最短路算法都不能过。

考虑用分块的思想来优化建图。

Pi>sqrt(n),暴力加入每一条边,每次最多sqrt(n)条边。

Pi≤sqrt(n),对于每个点添加sqrt(n)个辅助点,一层一层走,边数是O(n*sqrt(n))的。

总边数和总点数都是O(n*sqrt(n))。

块不能太大 不然爆内存 块最大100


#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define V G[p].v
#define P(x,y) ((x)*n+(y))
using namespace std;

inline char nc()
{
	static char buf[100000],*p1=buf,*p2=buf;
	if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
	return *p1++;
}

inline void read(int &x)
{
	char c=nc(),b=1;
	for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
	for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

const int N=4000005;
const int M=15000005;

struct edge{
	int v,w;
	int next;
};

edge G[M];
int head[N],inum;

inline void add(int u,int v,int w,int p){
	G[p].v=v; G[p].w=w; G[p].next=head[u]; head[u]=p;
}

const int ND=N;
int Q[ND],l,r;
int ins[N],dis[N];

int n,m,S,T,B;
int b[30005],p[30005];

inline void SPFA(int S){
	int u;
	for (int i=1;i<=P(B,n);i++) 
		dis[i]=1<<30,ins[i]=0;
	l=r=-1;
	dis[S]=0; Q[(++r)%ND]=S; ins[S]=1;
	while (l!=r){
		u=Q[(++l)%ND]; ins[u]=0;
		for (int p=head[u];p;p=G[p].next)
			if (dis[V]>dis[u]+G[p].w)
			{
				dis[V]=dis[u]+G[p].w;
				if (!ins[V])
					Q[(++r)%ND]=V,ins[V]=1;
			}
	}
}

int main()
{
	freopen("t.in","r",stdin);
	freopen("t.out","w",stdout);
	read(n); read(m);
	for (int i=1;i<=m;i++) read(b[i]),b[i]++,read(p[i]);
	S=b[1]; T=b[2];
	B=min((int)sqrt(n),100);
	for (int i=1;i<=B;i++)
		for (int j=1;j<=n;j++)
			add(P(i,j),j,0,++inum);
	for (int i=1;i<=B;i++)
		for (int j=1;j<=n-i;j++)
			add(P(i,j),P(i,j+i),1,++inum),add(P(i,j+i),P(i,j),1,++inum);  
	for (int i=1;i<=m;i++)
		if (p[i]<=B) 
			add(b[i],P(p[i],b[i]),0,++inum);  
		else
		{
			for(int j=1;b[i]+j*p[i]<=n;j++) add(b[i],b[i]+j*p[i],j,++inum);  
			for(int j=1;b[i]-j*p[i]>=1;j++) add(b[i],b[i]-j*p[i],j,++inum);
		}
	SPFA(S);
	if (dis[T]==1<<30)
		printf("-1\n");
	else  
		printf("%d\n",dis[T]);  
	return 0;  
}



你可能感兴趣的:([SPFA 分块建图] BZOJ 4070 [Apio2015]雅加达的摩天楼)