题目传送门
半夜打CF,实在熬不住,想了思路就睡了
思路:
十分明显的建边,建好边后算出每一个点的dis(就是题目中所说的时间)
然后从小到大枚举
n
n
n个可能的起始时间,维护结束时间的变化即可
对于结束时间的维护:
考虑枚举到
i
i
i并且已用
i
i
i更新了答案,那么由于接下来会枚举的起始时间(升序枚举)一定大于当前的时间,影响就是会令当前点的时间花费由
t
i
→
t
i
+
k
t_i\to t_i+k
ti→ti+k,用新的
t
i
t_i
ti更新结束时间即可
code:
打的比较丑陋
#include<iostream>
#include<algorithm>
#include<vector>
#define del(x,y) ((x-y+k)%k)
#define _bp __builtin_popcount
using namespace std;
typedef long long ll;
const int N = 2e5 + 5,M=35,mod=3;
int n,m,k;
int a[N];
bool vis[N];
ll dis[N];
pair<ll,ll> b[N];
vector<int>G[N];
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
void dfs(int u) {
if(vis[u]) return ;
vis[u]=1,dis[u]=0;
for(int v:G[u]) {
dfs(v);
dis[u]=max(dis[u],dis[v]+del(a[v],a[u]));
}
}
int main() {
int T;scanf("%d",&T);while(T--) {
n=read(),m=read(),k=read();
for(int i=1;i<=n;i++) a[i]=read(),G[i].clear(),vis[i]=0;
for(int i=1,u,v;i<=m;i++) {
u=read(),v=read();
G[u].push_back(v);
}
for(int i=1;i<=n;i++) dfs(i);
ll MAX=0,ans=1e18;
for(int i=1;i<=n;i++) {
b[i]=make_pair(a[i],a[i]+dis[i]);
MAX=max(MAX,b[i].second);
}
sort(b+1,b+1+n);
for(int i=1;i<=n;i++) {
ans=min(ans,MAX-b[i].first);
MAX=max(MAX,b[i].second+k);
}
printf("%lld\n",ans);
}
}