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

来源:互联网 发布:mac下ant环境变量配置 编辑:程序博客网 时间:2024/04/27 14:23

最坏情况有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;  }



0 0