把航班按出发时间从小到大排序。从前往后扫,求出dp[i]表示i时刻全都已出发的最小花费(i时刻全部已出发,也就是说可选航班是一个时间均小于i的前缀,在这些航班中选择n个人的最小花费,具体处理见代码)。类似的,从后往前扫,求出dp1[i]表示i时刻开始走,全部返回的最小花费(也就是说可选航班是一个时间均大于i的后缀)。然后枚举i时刻全部出发,则i+k+1时刻开始返回,更新答案。
#include <bits/stdc++.h>
using namespace std;
#define pa pair<int,int>
#define ll long long
#define inf 1LL<<60
#define N 1000005
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;
}
int n,m,k,mn[N],T=0;//dp1[i] i时刻回所有人的最小花费
ll dp[N],dp1[N];//dp[i] i时刻出发所有人的最小花费。
struct node{
int d,s,t,v;
}a[N];
inline bool cmp(node x,node y){return x.d<y.d;}
int main(){
// freopen("a.in","r",stdin);
n=read();m=read();k=read();
for(int i=1;i<=m;++i)
a[i].d=read(),a[i].s=read(),a[i].t=read(),a[i].v=read(),T=max(T,a[i].d);
sort(a+1,a+m+1,cmp);int tot=0;ll sum=0;
memset(mn,0,sizeof(mn));
for(int i=1;i<=T;++i) dp[i]=inf;
for(int i=1;i<=m;++i){
if(a[i].s==0) continue;
if(mn[a[i].s]==0) mn[a[i].s]=a[i].v,tot++,sum+=a[i].v;
else if(a[i].v<mn[a[i].s]) sum+=a[i].v-mn[a[i].s],mn[a[i].s]=a[i].v;
if(tot==n) dp[a[i].d]=sum;
}int s=1;
while(dp[s]==inf&&s<=T) ++s;
if(s>T){puts("-1");return 0;}
for(int i=s+1;i<=T;++i) dp[i]=min(dp[i],dp[i-1]);
for(int i=1;i<=T;++i) dp1[i]=inf;memset(mn,0,sizeof(mn));
tot=0;sum=0;
for(int i=m;i>=1;--i){
if(a[i].t==0) continue;
if(mn[a[i].t]==0) mn[a[i].t]=a[i].v,tot++,sum+=a[i].v;
else if(a[i].v<mn[a[i].t]) sum+=a[i].v-mn[a[i].t],mn[a[i].t]=a[i].v;
if(tot==n) dp1[a[i].d]=sum;
}s=T;
while(dp1[s]==inf&&s>=1) --s;
if(s<1){puts("-1");return 0;}
for(int i=s-1;i>=1;--i) dp1[i]=min(dp1[i],dp1[i+1]);
ll ans=inf;
for(int i=1;i+k+1<=T;++i){
if(dp[i]==inf||dp1[i+k+1]==inf) continue;
ans=min(ans,dp[i]+dp1[i+k+1]);
}
if(ans==inf) puts("-1");
else printf("%I64d\n",ans);
return 0;
}