【问题描述】
有 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]);
}