题目链接
这道题细节上的处理是真的比较容易的忽略了。
就譬如说,题目中说到的,从S到点x的一条路径上的两个点,这句话很关键。
我们都很容易的想到应该取次大值,但是次大值首先是根据最大值决定的,那么也就代表了最大值必须也是这条路径上的,次大值也是这条路径上的,不能取一条边的最大值,再取另一条其他边的最大值,组成最大值和次大值这样的组合是不行的。
那么,你继承最大值的时候,我们有时候会忽略一些最大值的答案,因为选取到x点的时候,可能用到的最大值和次大值,在选取x点后面的点y的时候,可能y的最大值,是到x的另一条路径上的最大值,但是从x到y路径上可能会形成最大值或者次大值的这种情况,所以,我们需要考虑这几个细节。
做法:Tarjan缩点+拓扑DP
做法是比较容易口糊出来的,但是dp确实要很细才行。
于是,为了避免有遗漏的,或者是保证取的是同一条路径上的,我们开了两个二维的dp来维护,其中,一个dp表示的是到达该点时候的同一条路径上过来的最大值和次大值,其中以次大值最大为目的。另一个二维dp呢,维护的是从起点开始,到该点的全体最大值和次大值,也就是不要求最大值和次大值在同一条路径上。
但是注意,我们这里处理最大值和次大值都是严格最大和严格次大,不允许相等。
然后,我们就是一个个的往后推下去就可以了,对于这个DAG图推dp,拓扑是最优的选择了。
对了,关于最大值和次大值的处理,因为要严格,所以,我们可以利用先放入数组,在用unique去重这样的操作,比较的简单。
给一组强样例,是根据我上面写到的两个细节来描绘的:
7 9 6 1
1 9 2 8 3 4 9
1 2
2 3
3 2
1 4
4 5
5 4
3 6
5 6
6 7
2 3 4 5 6 7
ans:2 2 3 3 4 8
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
//#include <unordered_map>
//#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f3f3f3f3f
#define eps 1e-8
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 4e5 + 7;
int N, M, Q, S, a[maxN];
struct Graph
{
int head[maxN], cnt;
struct Eddge
{
int nex, to;
Eddge(int a=-1, int b=0):nex(a), to(b) {}
}edge[maxN * 10];
inline void addEddge(int u, int v)
{
edge[cnt] = Eddge(head[u], v);
head[u] = cnt++;
}
inline void clear()
{
cnt = 0;
for(int i=1; i<=N; i++) head[i] = -1;
}
} Old, Now;
int dfn[maxN] = {0}, low[maxN], tot = 0, Stap[maxN], Stop = 0, Belong[maxN], Bcnt = 0, dp[maxN][2] = {0};
bool instack[maxN] = {false};
void Tarjan(int u)
{
dfn[u] = low[u] = ++tot;
Stap[++Stop] = u;
instack[u] = true;
for(int i=Old.head[u], v; ~i; i=Old.edge[i].nex)
{
v = Old.edge[i].to;
if(!dfn[v])
{
Tarjan(v);
low[u] = min(low[u], low[v]);
}
else if(instack[v]) low[u] = min(low[u], dfn[v]);
}
if(low[u] == dfn[u])
{
Bcnt++;
int v;
do
{
v = Stap[Stop--];
instack[v] = false;
Belong[v] = Bcnt;
if(a[v] > dp[Bcnt][0])
{
dp[Bcnt][1] = dp[Bcnt][0];
dp[Bcnt][0] = a[v];
}
else if(a[v] < dp[Bcnt][0] && a[v] > dp[Bcnt][1]) dp[Bcnt][1] = a[v];
} while(u ^ v);
}
}
int du[maxN] = {0}, ans[maxN][2] = {0}, mx[maxN][2];
void tp_sort()
{
for(int u=1; u<=N; u++)
{
if(!dfn[u]) continue;
for(int i=Old.head[u], v; ~i; i=Old.edge[i].nex)
{
v = Old.edge[i].to;
if(Belong[u] == Belong[v]) continue;
Now.addEddge(Belong[u], Belong[v]);
du[Belong[v]] ++;
}
}
queue<int> Q;
Q.push(Belong[S]);
for(int i=1; i<=Bcnt; i++) { ans[i][0] = dp[i][0]; ans[i][1] = dp[i][1]; mx[i][0] = dp[i][0]; mx[i][1] = dp[i][1]; }
int u, work[6] = {0}, len;
while(!Q.empty())
{
u = Q.front(); Q.pop();
for(int i=Now.head[u], v; ~i; i=Now.edge[i].nex)
{
v = Now.edge[i].to;
du[v] --;
len = 0;
work[++len] = ans[u][0]; work[++len] = ans[u][1]; work[++len] = dp[v][0]; work[++len] = dp[v][1];
sort(work + 1, work + len + 1);
len = (int)(unique(work + 1, work + len + 1) - work - 1);
if(work[len - 1] > ans[v][1])
{
ans[v][0] = work[len];
ans[v][1] = work[len - 1];
}
if(mx[u][0] > dp[v][0])
{
if(ans[v][1] < dp[v][0]) { ans[v][0] = mx[u][0]; ans[v][1] = dp[v][0]; }
}
else if(mx[u][0] < dp[v][0])
{
if(mx[u][0] > dp[v][1] && mx[u][0] > ans[v][1]) ans[v][1] = mx[u][0];
}
else
{
if(mx[u][1] > dp[v][1] && mx[u][1] > ans[v][1]) ans[v][1] = mx[u][1];
}
len = 0;
work[++len] = mx[u][0]; work[++len] = mx[u][1]; work[++len] = mx[v][0]; work[++len] = mx[v][1];
sort(work + 1, work + len + 1);
len = (int)(unique(work + 1, work + len + 1) - work - 1);
mx[v][0] = work[len]; mx[v][1] = work[len - 1];
if(!du[v]) Q.push(v);
}
}
}
inline void init()
{
Old.clear(); Now.clear();
}
int main()
{
scanf("%d%d%d%d", &N, &M, &Q, &S);
init();
for(int i=1; i<=N; i++) scanf("%d", &a[i]);
for(int i=1, u, v; i<=M; i++)
{
scanf("%d%d", &u, &v);
Old.addEddge(u, v);
}
Tarjan(S);
tp_sort();
for(int i=1, id; i<=Q; i++)
{
scanf("%d", &id);
if(!dfn[id]) printf("-1");
else printf("%d", ans[Belong[id]][1]);
printf(i == Q ? "\n" : " ");
}
return 0;
}