[AOIP 2015] 雅加达的摩天楼

题目描述:

qwq…

题目分析:

其实就是个最短路啊,然后发现建的边最多会有 N 2 条…
所以我们考虑用分块的思想来优化建图。
Pi>sqrt(n),暴力加入每一条边,每次最多sqrt(n)条边。
Pi≤sqrt(n),对于每个点添加sqrt(n)个辅助点,这里可以理解成一栋楼有许多层,每一层一步能走的范围都不同,然后每一层分别连边,每一层到楼底连边。对于一只doge,从楼底到Pi对应的楼层连边。边数是O(n*sqrt(n))的。
跑一下SPFA就可以了…

题目链接:

Luogu 3645

Ac 代码:

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <queue>
#include <cmath>
#include <cstring>
const int maxm=30005*800;
int cnt;
int n,m,block;
int head[maxm],net[maxm],cost[maxm],to[maxm];
int dis[maxm],vis[maxm];
std::queue <int> dl;
inline void addedge(int u,int v,int c)
{
    cnt++;
    to[cnt]=v,cost[cnt]=c,net[cnt]=head[u],head[u]=cnt;
}
inline int SPFA(int s,int t)
{
    memset(dis,127/3,sizeof(dis));
    dl.push(s),vis[s]=1;
    dis[s]=0;
    while(!dl.empty())
    {
        int now=dl.front();
        dl.pop();
        vis[now]=0;
        for(int i=head[now];i;i=net[i])
        if(dis[to[i]]>dis[now]+cost[i])
        {
            dis[to[i]]=dis[now]+cost[i];
            if(!vis[to[i]]) vis[to[i]]=1,dl.push(to[i]);
        }
    }
    return dis[t]==dis[0]?-1:dis[t];
}
int main()
{
    scanf("%d%d",&n,&m);
    block=std::min((int)std::sqrt(n),100);
    for(int i=1;i<=block;i++)
     for(int j=1;j<=n;j++)
      {
        addedge(i*n+j,j,0);
        if(j+i<=n) addedge(i*n+j,i*n+j+i,1),addedge(i*n+j+i,i*n+j,1);
      }
    int s,t;
    for(int i=1;i<=m;i++)
    {
        int b,p;
        scanf("%d%d",&b,&p);
        b++;
        if(i==1) s=b;
        if(i==2) t=b;
        if(p>block)
        {
            for(int j=1;b+j*p<=n;j++) addedge(b,b+j*p,j);
            for(int j=1;b-j*p>=1;j++) addedge(b,b-j*p,j); 
        }
        else addedge(b,b+p*n,0);
    }
    printf("%d\n",SPFA(s,t));
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_35914587/article/details/80290028