• [luoguP1119]灾后重建


     题目链接

    毒瘤题

    卡spfa

    可能dij也卡,没试过

    然后放floyd过了

    但其实spfa很好打,虽然只有60

    让我们来分析一下spfa的效率,假设这个出题人极其毒瘤,出网格图

    又因为是在线询问,所以对于每次询问都得跑一次spfa

    所以效率上界为$O(n*m*Q)$

    代入一下最坏情况,$200*19900*50000=199000000000$

    嗯,1.99*(10^11),成功炸飞

    但是spfa特别好想也特别好打

    在松弛的时候多判一下$if(t[u]>T||t[v]>T)continue$就好

    其他都是标准spfa操作

    题目中给的t是有序的,如果是无序的需要离线处理排序一下

    Code(spfa):

    #include <cstdio>
    #include <cstring>
    using namespace std;
    #define N 80000
    #define inf (1<<30)
    int n,m,t[N];
    int cnt,head[N];
    int d[N],q[N];
    bool vis[N];
    struct edge{int to,next,v;}e[N<<1];
    void ins(int u,int v,int w){
        e[++cnt].to=v;e[cnt].next=head[u];e[cnt].v=w;head[u]=cnt;
        e[++cnt].to=u;e[cnt].next=head[v];e[cnt].v=w;head[v]=cnt;
    }
    bool spfa(int s,int ttt,int tt){
        for(int i=1;i<=n;i++)d[i]=inf;
        memset(vis,0,sizeof(vis));
        int l=0,r=1;
        d[s]=0;q[0]=s;vis[s]=1;
        while(l<r){
            int u=q[l++];
            for(int i=head[u];i;i=e[i].next){
                int v=e[i].to;
                if(t[u]>tt||t[v]>tt)continue;
                if(d[v]>d[u]+e[i].v){
                    d[v]=d[u]+e[i].v;
                    if(!vis[v])vis[v]=1,q[r++]=v;
                }
            }
            vis[u]=0;
        }
        if(d[ttt]==inf)return 0;
        return 1;
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%d",&t[i]);
        for(int i=1;i<=m;i++){
            int x,y,w;
            scanf("%d%d%d",&x,&y,&w);
            x++;y++;
            ins(x,y,w);
        }
        int Q;
        scanf("%d",&Q);
        while(Q--){
            int x,y,T;
            scanf("%d%d%d",&x,&y,&T);
            if(spfa(x+1,y+1,T))printf("%d
    ",d[y+1]);
            else printf("-1
    ");
        }
        return 0;
    }

    好了接下来上正解

    观察到t和每个询问里面的T是有序的

    所以对于每个询问的T我们只要松弛已经修好的村庄就好了

    然后如果出发点/终点还没修好那么肯定也没法到,特判一下

    注意要建无向边

    其实floyd比spfa还好打(雾)

    Code(floyd):

    #include <cstdio>
    #include <cstring>
    using namespace std;
    #define inf 0x3f3f3f3f
    int f[210][210],t[40010],n,m,k;
    int min(int x,int y){return x<y?x:y;}
    int main(){
        scanf("%d%d",&n,&m);
        memset(f,0x3f,sizeof(f));
        for(int i=0;i<n;i++)
            scanf("%d",&t[i]),f[i][i]=0;
        for(int i=0;i<m;i++){
            int x,y,w;
            scanf("%d%d%d",&x,&y,&w);
            f[x][y]=f[y][x]=w;
        }
        int Q;
        scanf("%d",&Q);
        while(Q--){
            int x,y,w;
            scanf("%d%d%d",&x,&y,&w);
            while(t[k]<=w&&k<=n){
                for(int i=0;i<n;i++)
                    for(int j=0;j<n;j++)
                        f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
                k++;
            }
            if(f[x][y]==inf||t[x]>w||t[y]>w)printf("-1
    ");
            else printf("%d
    ",f[x][y]);
        }
        return 0;
    }
  • 相关阅读:
    SQL Server游标的使用【转】
    Window.Open参数、返回值
    .NET中class和struct的区别
    MVC中的几个问题汇总
    委托
    Hadoop集群环境搭建
    数学问题
    Ubuntu命令模式基础
    递归与分治-合并排序、快速排序以及循环赛问题
    Mongodb基础
  • 原文地址:https://www.cnblogs.com/henry-1202/p/9362507.html
Copyright © 2020-2023  润新知