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

分层图最短路,令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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值