思路:
- 票按时间升序排序
- 正着扫一遍得到start[i],表示会议从第i天开始,到达的人的花费,大于初始化值表示人未到齐
- 反着扫一遍得到end[i],表示第i天已回家的人的花费,大于初始化值表示人未全回
- 枚举会议开始的那一天 i ,则 ans=min(ans,start[i]+end[i+k+1])
代码:
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e6+7;
const int MAXM = 1e5+7;
const int INF = 0x3fff3fff;
const double eps=1e-6;
typedef long long LL;
int n,m,k;
struct P{
int day,u,v,cost;
bool operator < (const P &x)const{
if(day!=x.day)return day<x.day;
else return cost-x.cost;
}
};
P a[MAXN];
LL a2[MAXN],b[MAXN];
LL cost[MAXN];
int main()
{
while(cin>>n>>m>>k){
for(int i=0;i<m;i++){
P tmp;
scanf("%d%d%d%d",&tmp.day,&tmp.u,&tmp.v,&tmp.cost);
a[i]=tmp;
}
sort(a,a+m);
for(int i=0;i<MAXN;i++)cost[i]=1e12;
int cc=0;
LL now=0;
for(int i=0;i<n;i++)now+=cost[i];
for(int i=0;i<MAXN;i++){
while(cc<m&&a[cc].day==i){
if(a[cc].v==0&&a[cc].cost<cost[a[cc].u])
now+=a[cc].cost-cost[a[cc].u],cost[a[cc].u]=a[cc].cost;
cc++;
}
a2[i]=now;
}
for(int i=0;i<MAXN;i++)cost[i]=1e12;
cc=m-1;
now=0;
for(int i=0;i<n;i++)now+=cost[i];
for(int i=MAXN-1;i>=0;i--){
while(cc>=0&&a[cc].day==i){
if(a[cc].u==0&&a[cc].cost<cost[a[cc].v])
now+=a[cc].cost-cost[a[cc].v],cost[a[cc].v]=a[cc].cost;
cc--;
}
b[i]=now;
}
LL ans=1e18;
for(int i=0;i<MAXN-k-1;i++)ans=min(ans,a2[i]+b[i+k+1]);//,cout<<a[i].day<<endl;
ans>1e12?cout<<-1<<endl:cout<<ans<<endl;
}
return 0;
}