//tyvj1609
背景 Background
AndyBear 生日模拟赛 第三题
描述 Description
小熊BIBO要去给熊姥姥送蜂蜜。在去姥姥家的路上,要经过若干个村庄,村庄和村庄之间有小路相连,每条路都有不同的通过时间。每个村庄里都有很多好玩的东西,比如熊大叔的玩具店,还有兔大嫂的游乐城,所以每个村庄都对BIBO有一个吸引值F,如果小熊BIBO经过的某个村庄的吸引值太大,她就有可能留在那不走了! 现在,小熊BIBO希望在不超过T的时间内到达姥姥家,她想知道,在满足路上时间不超过T的情况下,路过的村庄的最大的吸引值最小是多少?
输入格式 Input Format
输入文件的第一行,有5个数字,n,m,u,v,T。 代表有n个村庄,m条双向小路,小熊BIBO要从u前往v,时间限制为T。
接下来的n行,每行1个数字,表示第i个村庄的吸引值为Fi。
接下来的m行,每行3个数字,x,y,c。表示有一条双向小路,连接的是x和y,需要的通过时间为c。
输出格式 Output Format
输出仅包含一个数字,表示从u到v,在时间不超过T的情况下,所经过的城市的最大吸引值最小是多少。
如果不能到达,请输出-1
样例输入 Sample Input [复制数据]
4 4 2 3 8856102 1 22 4 11 3 43 4 3
样例输出 Sample Output [复制数据]
8解释: 2->1->3. 其中城市1的吸引值最大,为8.
时间限制 Time Limitation
各个测试点1s
注释 Hint
对于60%的数据,满足n<=200,m<=10000,T<=200
对于100%的数据,满足n<=10000,m<=50000,T<=10^9
对于100%的数据,满足0<=ci,fi<=10^9,输入数据有重边。
弄死过不到,汪维正的建图的艺术里面的例题。
没有难度。二分,spfa,前向星,slf,就这些知识点。
和以前的一道收费站问题一模一样。
注意点:
1、边表排序的时候,首先以from,再以value排序。(后面这点主要是为了避免有重边的情况,使点多次入队)
2、不确定边的正负的时候最好用spfa
3、slf要注意队列l、r都为0的情况
4、二分解空间的时候,要注意减少解空间。(如此题,既然解是attract值中的一个,就不应将二分空间扩大了)
/* *\
WA20 二分右边界sum是吸引值总和,错算成是时间总和
没有判断
没有判断起点和终点吸引度是否大于二分mid值
无向图边的数量没有加倍
无解时没有输出-1
WA70 数据范围是10^9,用long long。
WA20 long long不能用printf和scanf
WA70 改的时候改错了,把-1改错成ans了
又加了一个SLF优化
TL 原来错的那组超时了
WA90 发现二分写错了,应该二分attract值,
而不是二分答案,超时的那组又错了
\* */
#include <cstdio>
#include <iostream>
#include <cstdlib>
struct ftv
{
long f;
long t;
long long v;
};
long n;long m;long u;long v;long long t;
long f[10002];
long long attract[10002];
const long long oo = 0x7fffffffff000000ll;
ftv bian[50002];
long top = 0;
long long sum = 0;
long que[10000000];
long long dist[10002];
bool used[10002];
void insert(long x,long y,long long c)
{
top++;
bian[top].f = x;
bian[top].t = y;
bian[top].v = c;
}
int bigger(const void* a,const void* b)
{
ftv* aa = (ftv*)a;
ftv* bb = (ftv*)b;
long aaa = aa->f;
long bbb = bb->f;
if (aaa>bbb)
{
return 1;
}
else if (aaa==bbb)
{
return 0;
}
else
return -1;
}
bool can(long long mid)
{
if (attract[v]>mid||attract[u]>mid)
return false;
//排除不可能的值
long long l=0;long long r=0;
for (long i=1;i<n+1;i++)
{
dist[i] = oo;
}
/*
for (long i=f[u];i<m+1;i++)
{
if (bian[i].f != u)
break;
if (attract[bian[i].t]<=mid&&bian[i].v<=t)
dist[bian[i].t] = bian[i].v;
}*/
r++;
que[r] = u;
dist[u] = 0;
while (l<r)
{
long now = que[++l];
used[now] = false;
for (long i=f[now];i<m+1;i++)
{
if (bian[i].f!=now) break;
if (attract[bian[i].t]<=mid
&&dist[bian[i].t]>dist[now]+bian[i].v)
//不能加的边
{
dist[bian[i].t]=dist[now]+bian[i].v;
if (!used[bian[i].t])
{
if (l==0||dist[que[l+1]]<=dist[bian[i].t])
{
used[bian[i].t] = true;
que[++r] = bian[i].t;
}
else
{
used[bian[i].t] = true;
que[l--] = bian[i].t;
}
}
}
}
}
if (dist[v]<=t)
return true;
else
return false;
}
int main()
{
freopen("1609.in","r",stdin);
freopen("1609.out","w",stdout);
//scanf("%ld %ld %ld %ld %ld",&n,&m,&u,&v,&t);
std::cin >> n >> m >> u >> v >> t;
for (long i=1;i<n+1;i++)
{
//scanf("%ld",attract+i);
std::cin >> attract[i];
sum += attract[i];
}
for (long i=1;i<m+1;i++)
{
long x;long y;long long c;
//scanf("%ld %ld %ld",&x,&y,&c);
std::cin >> x >> y >> c;
insert(x,y,c);
insert(y,x,c);
}
m*=2;
qsort(bian+1,m,sizeof(ftv),&bigger);
for (long i=1;i<m+1;i++)
if (f[bian[i].f]==0)
f[bian[i].f]=i;
long long l=0;long long r=sum;
long long ans=oo;
while (l<=r)
{
long long mid = (l+r)>>1;
if (can(mid))
{
if (mid<ans)
ans = mid;
r = mid-1;
}
else
l = mid+1;
}
if (ans < oo)
std::cout << ans;
else std::cout << -1;
}