• Codeforces-1696 D: Permutation Graph【构造、分治、数据结构】


    Codeforces-1696 D: Permutation Graph

    题目传送门:Codeforces-1696 D: Permutation Graph

    题目

    题目截图

    在这里插入图片描述

    样例描述

    在这里插入图片描述
    在这里插入图片描述

    题目大意

      给定一个 1 ⋯ n 1 \cdots n 1n 的排列,对于一个连续的区间 a i ⋯ a j a_i \cdots a_j aiaj,若 a i a_i ai 是这段区间的最小/最大值,同时, a j a_j aj 也是这段区间的最小/最大值,那么我们可以在 i , j i, j i,j 结点上连一条无向边。问这样构造出的图,从 1 1 1 n n n 的最短路径。

    题目解析

      首先暴力是肯定不行的,因为若是一个单调的数组,能连的边是 n 2 n^2 n2 级别的。
      这道题表面上是最短路径,实际上是考察必经结点。现在假设 a 1 ⋯ a n a_1 \cdots a_n a1an 的最大值在 a 2 ⋯ a n − 1 a_2 \cdots a_{n-1} a2an1 中,那么一个显然的结论是,这种情况下我们是无法绕过最大值从 1 1 1 达到 n n n 的,最小值同理。那么其中的最大值就变成了一个必经的结点 k k k。那么这样的必经之路有多少呢,显然 [ 1 , k ) [1,k) [1,k) 中的最小值, ( k , n ] (k,n] (k,n] 中的最小值都是必经之路,之后我们递归向左向右寻找这种必经之路,就能形成 1 1 1···最小-最大-最小··· n n n 这样的路径,显然,只存在必经之路的路径是最短的。

    Code

    #include <bits/stdc++.h>
    using namespace std;
    
    
    const int maxn = 6e5 + 7;
    int log_2[maxn];
    struct P {
        int v, id;
    }mx[maxn][18], mn[maxn][18];
    
    void setST(const vector<int>& a) {
        log_2[0] = -1;
        for(int i=0; i<a.size(); ++i) {
            mx[i][0].v = mn[i][0].v = a[i];
            mx[i][0].id = mn[i][0].id = i;
            log_2[i+1] = (((i+1)&i) == 0)?log_2[i]+1: log_2[i];
        }
        for(int j=1; j<18; ++j)
            for(int i=0; i<a.size(); ++i) {
                mx[i][j] = (mx[i][j-1].v < mx[i+(1<<(j-1))][j-1].v)? mx[i+(1<<(j-1))][j-1]:mx[i][j-1];
                mn[i][j] = (mn[i][j-1].v > mn[i+(1<<(j-1))][j-1].v)? mn[i+(1<<(j-1))][j-1]:mn[i][j-1];
            }
    }
    
    int query_mx(int l, int r) {
        int k = log_2[r - l + 1];
        if(mx[l][k].v < mx[r - (1<<k) + 1][k].v)
            return mx[r - (1<<k) + 1][k].id;
        else return mx[l][k].id;
    }
    
    int query_mn(int l, int r) {
        int k = log_2[r - l + 1];
        if(mn[l][k].v > mn[r - (1<<k) + 1][k].v)
            return mn[r - (1<<k) + 1][k].id;
        else return mn[l][k].id;
    }
    
    void dfs(int l, int r, bool cur, bool dir, vector<int>& a, vector<int>& ans) {
        if(dir) {
            int idx = cur?query_mn(l, r):query_mx(l, r);
            if(l < idx) dfs(l, idx, cur^1, dir, a, ans);
            ans.emplace_back(idx);
        } else {
            int idx = cur?query_mn(l, r):query_mx(l, r);
            if(idx < r) dfs(idx, r, cur^1, dir, a, ans);
            ans.emplace_back(idx);
        }
    }
    
    int main() {
       int T, n;
       cin >> T;
       while(T--) {
            cin >> n;
            vector<int> a(n);
            for(int& i : a) cin >> i;
    
            if(n == 1) {
                cout << 0 << endl; continue;
            } else if(n == 2) {
                cout << 1 << endl; continue;
            }
    
            setST(a);
            vector<int> ans;
            int idx = query_mx(0, n - 1); ans.emplace_back(idx);
    
            if(0 < idx) dfs(0, idx, true, true, a, ans);
            if(idx < n - 1) dfs(idx, n - 1, true, false, a, ans);
    
            cout << ans.size() - 1 << endl;
       }
       return 0;
    }
    
    • 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
  • 相关阅读:
    路由器配置静态和默认路由实现VLAN之间的通信
    DOM
    go语言如何调用其他包中的函数
    单文件组件
    Java集合之List
    工厂模式有三个Level,你能用Go写到第几层?
    PMP微信群日常习题
    力扣面试题17.04:消失的数字
    【sass中文文档】
    轻松快速搭建一个本地的语音合成服务
  • 原文地址:https://blog.csdn.net/Sherlock_Holmewei/article/details/125541784