zoukankan      html  css  js  c++  java
  • 雨中冒险

    【问题描述】
    有 n 个节点,标号为 1..n。m 条双向公路连接着这些节点,其中第 i 条公路
    连接着 u_i 和 v_i,从一端走到另一端需要 w_i 秒。现在,小 Y 打算从学校回到
    家里。
    学校是节点 1,小 Y 家是节点 n,保证存在至少一条从节点 1 到节点 n 的路
    径。
    在第 0 秒,小 Y 身处节点 1,他的目标是尽早到达节点 n。根据天气预报,
    接下来会有 k 次暴雨,第 i 次暴雨的时间为第 l_i 秒至第 r_i 秒,保证每次暴雨
    的时间段互不重叠(包括起止时间)。由于小 Y 忘了带伞,因此在下雨期间,他
    只能躲在某个节点里面避雨。如果某一个时刻在下暴雨,而小 Y 还在某条公路上,
    那么他会被淋惨。
    为了帮助小 Y 尽快回到家,上帝决定实现小 Y 一个愿望。小 Y 可以指定某一
    条道路,然后这条道路两端的节点将合并成一个节点(合并出的节点拥有原来两
    个节点的所有出边)。
    请你帮小 Y 计算,在不被淋惨的前提下最早第多少秒他能回到自己家中?
    注:对于一场第 l..r 秒的暴雨,若小 Y 第 r 秒从节点出发,或者第 l 秒到
    达某个节点,那么他是不会淋到雨的。
    【输入】
    输入文件名:rain.in
    第一行三个数 n、m、k。
    接下来 m 行,第 i 行三个整数表示 u_i、v_i、w_i。
    接下来 k 行,第 i 行两个整数表示 l_i、r_i。全国信息学奥林匹克联赛(NOIP2016)模拟赛
    提高组 day1
    【输出】
    输出文件名:rain.out
    第一行一个整数,表示小 Y 最早第多少秒能回到家中。
    【数据范围】
    测试点 1..6:k = 0
    测试点 7..12:n、m、k≤10 3
    测试点 1..20:2≤n≤10 5 ,1≤m≤2*10 5 ,0≤k≤10 5 ,1≤w_i≤10 4 ,
    0≤l_i<r_i≤10 9 ,且保证输入的暴雨时间段互不相交、l_i 严格递增。

    首先,建立分层图:

    dist[i][0/1]表示i点,0表示未缩点,1表示已缩

    现在唯一的问题就是怎麽算出到达时间

    at[i][0/1]表示i点0/1状态的上一场雨的编号,令为l

    要幺直接走

    或者对于每一场雨的间隔走w,走最靠前的大于w的边权

    这个怎麽求?

    用倍增,存间隔长的最大值

    此题奇鬼无比,还要用set优化,玄学

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #include<set>
    using namespace std;
    typedef long long lol;
    typedef pair<int,int> zt;
    struct Node
    {
        int next,to;
        int dis;
    } edge[400005];
    int num,head[100005],n,m,k;
    int dist[100005][2],L[100005],R[100005],st[20][100005],p[100005];
    int at[100005][2];
    bool vis[100005][2];
    lol gi()
    {
        lol x=0;
        char ch=getchar();
        while (ch<'0'||ch>'9') ch=getchar();
        while (ch>='0'&&ch<='9')
        {
            x=x*10+ch-'0';
            ch=getchar();
        }
        return x;
    }
    void add(int u,int v,int d)
    {
        num++;
        edge[num].next=head[u];
        head[u]=num;
        edge[num].to=v;
        edge[num].dis=d;
    }
    int count(int x,int w,int &np,int as)
    {
        int i,l;
        l=as+1;
        x=max(R[as],x);
        if (L[as+1]-x>=w)
        {
            np=as;
            return x+w;
        }
        for (i=17; i>=0; i--)
        {
            if (l+(1<<i)<=k&&st[i][l]<w)
            {
                l+=(1<<i);
            }
        }
        np=l;
        return R[l]+w;
    }
    void SPFA()
    {
        memset(dist,127/3,sizeof(dist));
        set<zt>Q;
        Q.insert((zt){1,0});
        dist[1][0]=0;
        at[1][0]=0;
        while (Q.size())
        {
            zt u=*Q.begin();
            Q.erase(Q.begin());
            vis[u.first][u.second]=0;
            for (int i=head[u.first]; i; i=edge[i].next)
            {
                int v=edge[i].to,np1,np2;
                int s=0,ss=0;
                if (u.second==0)
                    s=count(dist[u.first][0],edge[i].dis,np1,at[u.first][0]);
                if (u.second==1)
                    ss=count(dist[u.first][1],edge[i].dis,np2,at[u.first][1]);
                if (u.second==0&&dist[v][0]>s)
                {
                    dist[v][0]=s;
                    at[v][0]=np1;
                    if (vis[v][0]==0)
                    {
                        vis[v][0]=1;
                        Q.insert((zt){v,0});
                    }
                }
                if (u.second==1&&dist[v][1]>ss)
                {
                    dist[v][1]=ss;
                    at[v][1]=np2;
                    if (vis[v][1]==0)
                    {
                        vis[v][1]=1;
                        Q.insert((zt){v,1});
                    }
                }
                if (u.second==0&&dist[v][1]>dist[u.first][0])
                {
                    dist[v][1]=dist[u.first][0];
                    at[v][1]=at[u.first][0];
                    if (vis[v][1]==0)
                    {
                        vis[v][1]=1;
                        Q.insert((zt){v,1});
                    }
                }
            }
        }
    }
    int main()
    {
        int u,v,i,j;
        int w;
        cin>>n>>m>>k;
        for (i=1; i<=m; i++)
        {
            u=gi();
            v=gi();
            w=gi();
            add(u,v,w);
            add(v,u,w);
        }
        L[k+1]=2e9;
        for (i=1; i<=k; i++)
        {
            L[i]=gi();
            R[i]=gi();
        }
        for (i=1; i<=k; i++)
            st[0][i]=L[i+1]-R[i],p[i]=max(st[0][i],p[i-1]);
        for (i=1; i<=17; i++)
        {
            for (j=1; j<=k; j++)
                if (j+(1<<i)-1<=k)
                {
                    st[i][j]=max(st[i-1][j],st[i-1][j+(1<<i-1)]);
                }
                else break;
        }
        SPFA();
        //for (i=1;i<=n;i++)
        //cout<<dist[i][0]<<' '<<dist[i][1]<<endl;
        cout<<min(dist[n][1],dist[n][0]);
    }
  • 相关阅读:
    2.2 列表推导和生成器表达式
    1.2 如何使用特殊方法
    Selenium安装方法
    Python中Selenium的使用方法
    BeautifulSoup4的使用方法
    (转)Python中sort和sorted的区别和使用方法
    (转)Python中random模块的几个常用函数
    PR中我的常用快捷键
    二、交互式运行环境——REPL
    一、Node.js概述
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/7554124.html
Copyright © 2011-2022 走看看