zoukankan      html  css  js  c++  java
  • BZOJ4070 [Apio2015]雅加达的摩天楼 【分块 + 最短路】

    题目链接

    BZOJ4070

    题解

    考虑暴力建图,将每个(B_i)向其能到的点连边,复杂度(O(sum frac{n}{p_i})),当(p)比较小时不适用
    考虑优化建图,每个(doge)能移动的点实际上是一组模(p)同余的点,那么只要对每个(p)(n)个点,然后内部距离为(p)的点连边,然后每个点向原来的点连边,如果某个点有步长为(p)(doge),则原点向该点连边,这样子每一层点数和边数都是(O(n))的,复杂度是(O(pn)),当(p)较小时使用

    如此可以得出最终算法,分块处理
    对于(p)较小的点优化建图,(p)较大的点暴力建图
    跑最短路即可

    如果是(dijsktra),复杂度(O(nsqrt{n}log(nsqrt{n})))
    但据说这里(spfa)快?

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<queue>
    #include<cstdio>
    #include<cmath>
    #include<map>
    #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define mp(a,b) make_pair<int,int>(a,b)
    #define cls(s) memset(s,0,sizeof(s))
    #define cp pair<int,int>
    #define LL long long int
    using namespace std;
    const int maxn = 4000005,maxm = 15000005,INF = 1000000000;
    inline int read(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    	return out * flag;
    }
    int h[maxn],ne = 1;
    struct EDGE{int to,nxt,w;}ed[maxm];
    inline void build(int u,int v,int w){
    	ed[++ne] = (EDGE){v,h[u],w}; h[u] = ne;
    }
    int n,m,B,d[maxn],inq[maxn],S,T;
    queue<int> q;
    void spfa(){
    	int E = B * n + n;
    	for (int i = 1; i <= E; i++) d[i] = INF;
    	d[S] = 0; q.push(S); int u;
    	while (!q.empty()){
    		u = q.front(); q.pop(); inq[u] = false;
    		Redge(u) if (d[to = ed[k].to] > d[u] + ed[k].w){
    			d[to] = d[u] + ed[k].w;
    			if (!inq[to]) q.push(to),inq[to] = true;
    		}
    	}
    }
    int main(){
    	n = read(); m = read(); B = min((int)sqrt(n),100);
    	for (int i = 1; i <= B; i++){
    		for (int j = 1; j <= i; j++){
    			for (int u = j; u + i <= n; u += i){
    				build(i * n + u,i * n + u + i,1);
    				build(i * n + u + i,i * n + u,1);
    			}
    		}
    		for (int j = 1; j <= n; j++)
    			build(i * n + j,j,0);
    	}
    	int x,p;
    	for (int t = 1; t <= m; t++){
    		x = read() + 1; p = read();
    		if (t == 1) S = x;
    		if (t == 2) T = x;
    		if (p > B){
    			for (int i = p,j = 1; x - i > 0; i += p,j++)
    				build(x,x - i,j);
    			for (int i = p,j = 1; x + i <= n; i += p,j++)
    				build(x,x + i,j);
    		}
    		else build(x,p * n + x,0);
    	}
    	spfa();
    	if (d[T] == INF) puts("-1");
    	else printf("%d
    ",d[T]);
    	return 0;
    }
    
    
  • 相关阅读:
    如何进入高效学习状态
    shell printf命令:格式化输出语句
    C# virtual、abstract
    git解决Could not execute editor
    go defer笔记
    git从其他分支提取文件merge到当前分支
    golang map
    状态模式
    golang单例模式
    go 单元测试时读取配置文件
  • 原文地址:https://www.cnblogs.com/Mychael/p/9185811.html
Copyright © 2011-2022 走看看