P7831 [CCO2021] Travelling Merchant

Description

https://www.luogu.com.cn/problem/P7831

Solution

妙妙题,丹砂失败了。警戒。

令 $i$ 点的答案为 $f_i$。首先先建反向边,拓扑排序把无解的判掉。

考虑当前图上 $r$ 最大的一条边 $(x,y,r,p)$,因为 $p\ge 0$,所以 $x$ 一定可以通过初值为 $r$ 永久不停的走,也就是 $f_x\gets \min {f_x,r}$。然后把这条边删掉。

每次删一条边以后,如果存在一个点的入度 $=0$,则把这个点入队。如果入队则说明目前这个点不存在任何一个环中,则用 DAG 图上 dp 的方法 $f_y\gets \min{f_y,\max{f_x-p,r}}$ 更新 $f_y$。

复杂度 $O(n+m\log m)$,瓶颈在于对 $r$ 排序。

总结一下,这题通过观察到最大的一条边在图上可以任意走的性质,用于贪心并结合拓扑排序,很喵喵啊。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define maxn 200005
#define put() putchar('\n')
#define Tp template<typename T>
#define Ts template<typename T,typename... Ar>
using namespace std;
Tp void read(T &x){
int f=1;x=0;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
x*=f;
}
namespace Debug{
Tp void _debug(char* f,T t){cerr<<f<<'='<<t<<endl;}
Ts void _debug(char* f,T x,Ar... y){while(*f!=',') cerr<<*f++;cerr<<'='<<x<<",";_debug(f+1,y...);}
#define gdb(...) _debug((char*)#__VA_ARGS__,__VA_ARGS__)
}using namespace Debug;
#define fi first
#define se second
#define mk make_pair
const int mod=1e9+7;
int power(int x,int y=mod-2) {
int sum=1;
while (y) {
if (y&1) sum=sum*x%mod;
x=x*x%mod;y>>=1;
}
return sum;
}
int n,m;
int head,h[maxn];
struct yyy {
int to,z,r,p,fm,flag;
void add(int x,int y,int R,int P) {
to=y;z=h[x];h[x]=head;r=R;p=P;fm=x;
}
}a[maxn];
int id[maxn],in[maxn];
bool cmp(int x,int y) {return a[x].r>a[y].r;}
queue<int>q;
int f[maxn];
const int inf=1e12;
void solve() {
int i,x;
while (!q.empty()) {
x=q.front();q.pop();
for (i=h[x];i;i=a[i].z) if (!a[i].flag) {
a[i].flag=1;
if (f[x]<inf) f[a[i].to]=min(f[a[i].to],max(f[x]-a[i].p,a[i].r));
if (!--in[a[i].to]) q.push(a[i].to);
}
}
}
signed main(void){
int i,j,x,y,z,val;
memset(f,0x3f,sizeof(f));
read(n);read(m);
for (i=1;i<=m;i++) {
read(x),read(y),read(z),read(val);
a[++head].add(y,x,z,val);
in[x]++;id[i]=i;
}
sort(id+1,id+1+m,cmp);
for (i=1;i<=n;i++) if (!in[i]) q.push(i);
for (i=1;i<=m;i++) {
solve();
if (a[id[i]].flag) continue;
a[id[i]].flag=1;
j=id[i];
f[a[j].to]=min(f[a[j].to],a[j].r);
if (!--in[a[j].to]) q.push(a[j].to);
}
for (i=1;i<=n;i++) printf("%lld ",f[i]>inf?-1:f[i]);put();
return 0;
}
//i=begin && g++ $i.cpp -o $i -std=c++14 -O2 && ./$i