[luogu7831]Travelling Merchant

考虑不断找到以下两种类型的边,并维护答案:

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

 

posted @ 2021-09-10 15:22  PYWBKTDA  阅读(59)  评论(0编辑  收藏  举报