披风

题目大意:给定一张有向图,每个点有点权。试找到一条路径,使得该路径上的点权最大值减去点权最小值最大,问这个差最大是多少。

暴力分数给的很足,但是我没有去打,我想的真解,结果正解还没有搞出来,真jb傻逼

正解是:tarjan缩点,然后跑两边拓扑dp,一次最小值,一次最大值,然后就没了

代码如下:

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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#include <bits/stdc++.h>
using namespace std;

typedef pair<int,int> pr;
const int N = 1e5 + 66, M = 5e5 + 66;

inline int read()
{
int s(0), w(1);
char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-') w = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * w;
}
inline void put(int x)
{
if (! x) putchar('0');
if (x < 0) putchar('-'), x = -x;
int num(0); char c[66];
while (x) c[++ num] = x % 10 + 48, x /= 10;
while (num) putchar(c[num --]);
return (void)(putchar('\n'));
}

map<pr, bool>existed;
int ver[M], nex[M], head[N], cnt;

inline void add_edge(int x, int y)
{
ver[++ cnt] = y;
nex[cnt] = head[x];
return (void)(head[x] = cnt);
}

int n, m, top, tot, num, res;
int minv[N], maxv[N];
int dfn[N], low[N], sta[N], in[N], tar[N], v[N];

inline void tarjan(int x)
{
dfn[x] = low[x] = ++ tot, in[x] = 1, sta[++ top] = x;
int i, y;
for (i = head[x]; i; i = nex[i])
{
y = ver[i];
if (! dfn[y])
{
tarjan(y);
low[x] = min(low[x], low[y]);
}
else if (in[y]) low[x] = min(low[x], dfn[y]);
}
if (low[x] == dfn[x])
{
++ num;
do {
y = sta[top --], in[y] = 0;
tar[y] = num;
minv[num] = min(minv[num], v[y]);
maxv[num] = max(maxv[num], v[y]);
} while(x != y);
}
return;
}

int vers[M], nexs[M], heads[N], cnts, deg[N], deg1[N], maxv1[N];

inline void add(int x, int y)
{
vers[++ cnts] = y;
nexs[cnts] = heads[x];
++ deg[y];
return (void)(heads[x] = cnts);
}

inline void fuck1()
{
queue<int>q;
for (int i = 1; i <= num; ++ i)
{
if (! deg[i]) q.push(i);
maxv1[i] = maxv[i], deg1[i] = deg[i];
}
while (! q.empty())
{
int x = q.front(); q.pop();
for (int i = heads[x]; i; i = nexs[i])
{
int y = vers[i];
maxv[y] = max(maxv[y], maxv[x]);
if (! --deg1[y]) q.push(y);
}
res = max(res, maxv[x] - minv[x]);
}
return;
}

inline void fuck2()
{
queue<int>q;
for (int i = 1; i <= num; ++ i) if (! deg[i]) q.push(i);
while (! q.empty())
{
int x = q.front(); q.pop();
for (int i = heads[x]; i; i = nexs[i])
{
int y = vers[i];
minv[y] = min(minv[y], minv[x]);
if (! --deg[y]) q.push(y);
}
res = max(res, maxv1[x] - minv[x]);
}
}

signed main()
{
int i, x, y; n = read(), m = read();
memset(minv, 0x3f, sizeof minv), memset(maxv, 0xcf, sizeof maxv);
for (i = 1; i <= n; ++ i) v[i] = read();
for (i = 1; i <= m; ++ i)
{
x = read(), y = read();
if (existed[pr(x, y)]) continue;
add_edge(x, y);
existed[pr(x, y)] = 1;
}
for (i = 1; i <= n; ++ i) if (! dfn[i]) tarjan(i);

for (x = 1; x <= n; ++ x)
{
for (i = head[x]; i; i = nex[i])
{
y = ver[i];
if (tar[x] == tar[y]) continue;
add(tar[x], tar[y]);
}
}

fuck1(), fuck2();

put(res);
return 0;
}

总结:这次考试期望得分:100+60+0+60pts,实际得分:80+40+0+0,这跟期望得分差距也太大了吧,自己老是在后边,有种快起不来的感觉

第一题我傻逼没开ll

第二题思路错了,数据太水还给了40pts

第三题没时间看,

第四题题目审错了

我发誓以后无论什么题目,必须先打暴力

其实这次考试暴力分数给的非常足:100+60+60+60=280pts

第三题就tm是个搜索啊,第二题就tm是个傻逼拓扑啊,第一题就tm是个小学一年级都会的题吧

我感觉自己100+100+100+60没问题啊

是真tm操蛋