雨中冒险

【问题描述】
有 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

首先,建立分层图:

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

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

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

要幺直接走

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

这个怎麽求?

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

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

 

#include
#include
#include
#include
#include
#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<w)
        {
            l+=(1<<i);
        }
    }
    np=l;
    return R[l]+w;
}
void SPFA()
{
    memset(dist,127/3,sizeof(dist));
    setQ;
    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<1<=k)
            {
                st[i][j]=max(st[i-1][j],st[i-1][j+(1<1)]);
            }
            else break;
    }
    SPFA();
    //for (i=1;i<=n;i++)
    //cout<
    cout<1],dist[n][0]);
}

 

转载于:https://www.cnblogs.com/Y-E-T-I/p/7554124.html

你可能感兴趣的:(雨中冒险)