码迷,mamicode.com
首页 > Windows程序 > 详细

bzoj 4070: [Apio2015]雅加达的摩天楼

时间:2016-05-07 11:05:56      阅读:317      评论:0      收藏:0      [点我收藏+]

标签:

分层图最短路,令k=sqrt(n)
如果p>k,那么从这个点出发只需要连<sqrt(n)条边
如果p<k,这样的p只有k种
建有k+1层的分层图,把第0层视为每个位置的源点,对于p<k,从g[x][0]到g[x][p]连边,层内%p相同的点相邻的连距离为1的边
最后的建图:
第1层到第k层每层都向对应的第0层连边权是0的边
每一层相邻的%p相同的点互相连边权是1的边
对于每个>k的,从出发点向可以到达的点连距离=跳跃步数的边
发现这样内存不够,所以把k设小一点。
写错的地方:
1.少加了一种边
2.点数是30000*101 而不是30000*100
3.读错题
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<set>
#include<cmath>
#define ll long long
#define inf 1e9
#define eps 1e-10
#define N 3500010
#define md
using namespace std;
struct yts { int t,l,ne;} e[15000010];
int dis[N],v[N],q[N],g[30010][110];
bool vis[N];
set<int> st[30010];
int cnt,num,S,T;
void put(int x,int y,int l)
{
num++; e[num].t=y; e[num].l=l;
e[num].ne=v[x]; v[x]=num;
}
int spfa()
{
for (int i=1;i<=cnt;i++) dis[i]=inf;
int h=0,w=1; q[1]=S; dis[S]=0; vis[S]=1;
while (h!=w)
{
h++; if (h>cnt+2) h=1; int x=q[h];
for (int i=v[x];i;i=e[i].ne)
{
int y=e[i].t;
if (dis[y]>dis[x]+e[i].l)
{
dis[y]=dis[x]+e[i].l;
if (!vis[y])
{
vis[y]=1;
w++; if (w>cnt+2) w=1; q[w]=y;
}
}
}
vis[x]=0;
}
if (dis[T]==inf) return -1;
return dis[T];
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
int K=min(100,(int)sqrt(n));
for (int i=0;i<n;i++)
{
for (int j=0;j<=K;j++)
g[i][j]=++cnt;
for (int j=1;j<=K;j++)
put(g[i][j],g[i][0],0);
}
for (int i=1;i<=m;i++)
{
int x,p;
scanf("%d%d",&x,&p);
if (i==1) S=g[x][0];
if (i==2) T=g[x][0];
if (p>K)
{
for (int j=x-p;j>=0;j-=p) put(g[x][0],g[j][0],(x-j)/p);
for (int j=x+p;j<n;j+=p) put(g[x][0],g[j][0],(j-x)/p);
}
else
{
put(g[x][0],g[x][p],0);
if (st[p].find(x%p)==st[p].end())
{
st[p].insert(x%p);
for (int j=x%p;j+p<n;j+=p)
{
put(g[j][p],g[j+p][p],1);
put(g[j+p][p],g[j][p],1);
}
}
}
}
printf("%d\n",spfa());
return 0;
}

bzoj 4070: [Apio2015]雅加达的摩天楼

标签:

原文地址:http://blog.csdn.net/heheda_is_an_oier/article/details/51332860

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!