Speedrun
luckydrawbox · · 题解
又是一道赛后两分钟敲完的题。
题意
你有
求完成时间最晚与最早的任务的时间差的最小值。
分析
把题中的
有一个贪心的想法是让每个任务完成的时间尽量靠前,于是我们可以在
答案为
但是这样是错的,样例告诉我们,可以通过把完成时间最小的几个点的
可这样的时间复杂度仍高达
于是
代码
虽然题目给的就是拓扑序,但我还是用了拓扑排序
#include<bits/stdc++.h>
#define ll long long
using namespace std;
long long read(){
long long x=0,f=1;char ch=getchar();
while(!isdigit(ch))
{if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
void write(long long x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
const int N=2e5+10;
int t,n,m,k;
ll h[N],dep[N];
int head[N],ver[N],nxt[N],tot,in[N];
void add(int x,int y){
ver[++tot]=y;nxt[tot]=head[x];head[x]=tot;in[y]++;
}
queue<int>q;
void topu(){
while(q.size())q.pop();
for(int i=1;i<=n;i++){
if(!in[i])
q.push(i),dep[i]=0;
}
while(q.size()){
int x=q.front();q.pop();
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
dep[y]=max(dep[y],dep[x]+(h[x]>h[y]));
in[y]--;
if(!in[y])
q.push(y);
}
}
}
int a[N],top;
ll ch[N];
bool cmp(int x,int y){
return h[x]<h[y];
}
ll dfs(int x){
if(ch[x]!=-1)return ch[x];
ch[x]=(dep[x]+1)*k+h[x];
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
if(dep[x]+(h[x]>h[y])+1>dep[y])
ch[x]=max(ch[x],dfs(y));
}
return ch[x];
}
int main(){
t=read();
while(t--){
n=read();m=read();k=read();
for(int i=1;i<=n;i++){
h[i]=read();in[i]=head[i]=dep[i]=0;
ch[i]=-1;
}
tot=top=0;
for(int i=1;i<=m;i++){
int x=read(),y=read();
add(x,y);
}
for(int i=1;i<=n;i++)
if(!in[i])a[++top]=i;
sort(a+1,a+top+1,cmp);
topu();
ll mx=0,ans=1e18;
for(int i=1;i<=n;i++)
mx=max(mx,dep[i]*k+h[i]);
for(int i=1;i<=n;i++)dfs(i);
for(int i=1;i<=top;i++){
ans=min(ans,mx-h[a[i]]);
mx=max(mx,ch[a[i]]);
}
write(ans);puts("");
}
return 0;
}