考虑不断找到以下两种类型的边,并维护答案:
1.终点出度为0的边,那么此时即令$ans_{x}=\min(ans_{x},\max(r,ans_{y}-p))$
2.(在没有"终点出度为0的边时",即优先删除第1类边)剩余边中$r$最大的边,注意到能走到的每一个点都有出边,且其限制$r$都更小,那么即可令$ans_{x}=\min(ans_{x},r)$
进一步的,在维护答案后,注意到如果答案比该限制小,那么一定可以不用这条边,因此删去该边即可
关于此过程的维护,维护一个队列记录所有出度为0的点,以及将所有边先按照$r$从小到大排序即可
时间复杂度为$o(m\log m)$(排序),可以通过
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 200005 4 #define oo 0x3f3f3f3f 5 struct Data{ 6 int x,y,r,p; 7 bool operator < (const Data &k)const{ 8 return r>k.r; 9 } 10 }e[N]; 11 queue<int>q; 12 vector<int>v[N]; 13 int n,m,r[N],vis[N],ans[N]; 14 void del(int k){ 15 vis[k]=1; 16 if (--r[e[k].x]==0)q.push(e[k].x); 17 } 18 int main(){ 19 scanf("%d%d",&n,&m); 20 for(int i=1;i<=m;i++)scanf("%d%d%d%d",&e[i].x,&e[i].y,&e[i].r,&e[i].p); 21 sort(e+1,e+m+1); 22 for(int i=1;i<=m;i++){ 23 r[e[i].x]++; 24 v[e[i].y].push_back(i); 25 } 26 memset(ans,oo,sizeof(ans)); 27 for(int i=1;i<=n;i++) 28 if (!r[i])q.push(i); 29 for(int i=1;i<=m;i++){ 30 while (!q.empty()){ 31 int k=q.front(); 32 q.pop(); 33 for(int i=0;i<v[k].size();i++){ 34 int x=v[k][i]; 35 if (!vis[x]){ 36 if (ans[k]!=oo)ans[e[x].x]=min(ans[e[x].x],max(e[x].r,ans[k]-e[x].p)); 37 del(x); 38 } 39 } 40 } 41 if (!vis[i]){ 42 ans[e[i].x]=min(ans[e[i].x],e[i].r); 43 del(i); 44 } 45 } 46 for(int i=1;i<=n;i++) 47 if (ans[i]==oo)ans[i]=-1; 48 for(int i=1;i<n;i++)printf("%d ",ans[i]); 49 printf("%d\n",ans[n]); 50 return 0; 51 }View Code