调查任务【51nod 1815】【Tarjan+拓扑DP】

题目链接


这道题细节上的处理是真的比较容易的忽略了。

就譬如说,题目中说到的,从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;
}
发布了886 篇原创文章 · 获赞 1059 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/qq_41730082/article/details/105270693
今日推荐