結果

問題 No.1995 CHIKA Road
ユーザー log_Klog_K
提出日時 2023-06-26 10:57:49
言語 C++17
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 497 ms / 2,000 ms
コード長 13,216 bytes
コンパイル時間 2,837 ms
コンパイル使用メモリ 231,432 KB
実行使用メモリ 46,368 KB
最終ジャッジ日時 2023-09-16 04:01:07
合計ジャッジ時間 11,791 ms
ジャッジサーバーID
(参考情報)
judge13 / judge14
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 2 ms
4,376 KB
testcase_01 AC 1 ms
4,376 KB
testcase_02 AC 1 ms
4,376 KB
testcase_03 AC 1 ms
4,380 KB
testcase_04 AC 2 ms
4,376 KB
testcase_05 AC 2 ms
4,380 KB
testcase_06 AC 19 ms
5,696 KB
testcase_07 AC 72 ms
11,332 KB
testcase_08 AC 2 ms
4,380 KB
testcase_09 AC 2 ms
4,376 KB
testcase_10 AC 103 ms
14,804 KB
testcase_11 AC 497 ms
46,368 KB
testcase_12 AC 264 ms
31,212 KB
testcase_13 AC 130 ms
16,676 KB
testcase_14 AC 142 ms
17,144 KB
testcase_15 AC 415 ms
43,424 KB
testcase_16 AC 31 ms
7,132 KB
testcase_17 AC 176 ms
22,960 KB
testcase_18 AC 323 ms
31,884 KB
testcase_19 AC 334 ms
31,400 KB
testcase_20 AC 155 ms
18,680 KB
testcase_21 AC 141 ms
17,336 KB
testcase_22 AC 309 ms
31,428 KB
testcase_23 AC 76 ms
14,160 KB
testcase_24 AC 262 ms
28,332 KB
testcase_25 AC 41 ms
8,380 KB
testcase_26 AC 93 ms
14,888 KB
testcase_27 AC 251 ms
26,964 KB
testcase_28 AC 139 ms
17,132 KB
testcase_29 AC 318 ms
30,988 KB
testcase_30 AC 39 ms
8,232 KB
testcase_31 AC 18 ms
5,516 KB
testcase_32 AC 53 ms
9,332 KB
testcase_33 AC 249 ms
26,816 KB
testcase_34 AC 21 ms
6,140 KB
testcase_35 AC 85 ms
13,668 KB
testcase_36 AC 107 ms
15,308 KB
testcase_37 AC 293 ms
29,420 KB
testcase_38 AC 196 ms
23,844 KB
testcase_39 AC 17 ms
5,432 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#line 2 "library/Template.hpp"

/**
 * @brief Procon Template - テンプレート
 */

#include <bits/stdc++.h>
#define ALL(x) (x).begin(), (x).end()
#define RALL(x) (x).rbegin(), (x).rend()
#define SORT(x) sort(ALL(x))
#define RSORT(x) sort(RALL(x))
#define REV(x) reverse(ALL(x))
#define SETPRE(digit) fixed << setprecision(digit)
#define popcount(x) __builtin_popcount(x)
#define ACC(x) accumulate((x).begin(), (x).end(), 0LL)
using namespace std;

inline string Yn(bool flag){return (flag) ? "Yes" : "No";}
inline bool YnPrint(bool flag){cout << Yn(flag) << endl;return flag;}
inline string YN(bool flag){return (flag) ? "YES" : "NO";}
inline bool YNPrint(bool flag){cout << YN(flag) << endl;return flag;}
template<class T>
bool minin(T &src, const T &cmp){if(src > cmp){src = cmp; return true;}return false;}
template<class T>
bool maxin(T &src, const T &cmp){if(src < cmp){src = cmp; return true;}return false;}
template<typename T>
inline bool between(T min, T x, T max){return min <= x && x <= max;}
template<typename T>
inline T median(T a, T b, T c){return between(b, a, c) || between(c, a, b) ? a : (between(a, b, c) || between(c, b, a) ? b : c);}

using ll = long long;
using ull = unsigned long long;

const double PI = 3.141592653589793;
const double PI2 = PI * 2;
const double PI_2 = PI / 2;

const int INF_INT = numeric_limits<int>::max() / 2;
const long long INF_LL = numeric_limits<long long>::max() / 2LL;

template <typename T>
using vec = vector<T>;
using pi = pair<int, int>;
using pll = pair<ll, ll>;
using pd = pair<double, double>;
template <typename T>
using pq = priority_queue<T>;
template <typename T>
using rpq = priority_queue<T, vec<T>, greater<T>>;

const int dx4[4] = {1, 0, -1, 0};
const int dy4[4] = {0, -1, 0, 1};
const int dx8[8] = {1, 1, 0, -1, -1, -1, 0, 1};
const int dy8[8] = {0, -1, -1, -1, 0, 1, 1, 1};

template <typename T1, typename T2>
ostream &operator<<(ostream &os, const pair<T1, T2> &p){
    os << "{" << p.first << " " << p.second << "}";
    return os;
}

template <typename T1, typename T2>
istream &operator>>(istream &is, pair<T1, T2> &p){
    is >> p.first >> p.second;
    return is;
}

template <typename T>
ostream &operator<<(ostream &os, vector<T> &v){
    for (int i = 0; i < v.size(); ++i){
        os << v[i] << (i + 1 != v.size() ? " " : "");
    }
    return os;
}

template <typename T>
ostream &operator<<(ostream &os, vector<vector<T>> &v){
    for (int i = 0; i < v.size(); ++i){
        os << v[i] << "\n";
    }
    return os;
}

template <typename T>
istream &operator>>(istream &is, vector<T> &v){
    for (int i = 0; i < v.size(); ++i) is >> v[i];
    return is;
}

template <typename T>
istream &operator>>(istream &is, valarray<T> &v){
    for (int i = 0; i < v.size(); ++i) is >> v[i];
    return is;
}

template <typename T1, typename T2, typename T3>
pair<T1, T2> &operator+=(pair<T1, T2> &x, const T3 &y){
    x.first += y;
    x.second += y;
    return x;
}

template <typename T1, typename T2, typename T3>
pair<T1, T2> &operator-=(pair<T1, T2> &x, const T3 &y){
    x.first -= y;
    x.second -= y;
    return x;
}

ll modpow(ll a, ll b, ll m){
    ll p = 1, q = a;
    for (int i = 0; i < 63; ++i)
    {
        if ((b & (1LL << i)) != 0)
        {
            p *= q;
            p %= m;
        }
        q *= q;
        q %= m;
    }
    return p;
}

template <typename T>
inline long long EuclideanDist2(const pair<T, T> &p1, const pair<T, T> &p2){
    long long dx = (long long)p1.first - (long long)p2.first;
    long long dy = (long long)p1.second - (long long)p2.second;
    return dx * dx + dy * dy;
}

template <typename T>
inline long long EuclideanDist2(const pair<T, T> &p){
    return EuclideanDist2(p, make_pair(0, 0));
}

template <typename T>
inline double EuclideanDist(const pair<T, T> &p1, const pair<T, T> &p2){
    return sqrt((double)EuclideanDist2(p1, p2));
}

template <typename T>
inline double EuclideanDist(const pair<T, T> &p){
    return sqrt((double)EuclideanDist2(p));
}

template<typename T>
inline long long ManhattanDist(const pair<T, T> &p1, const pair<T, T> &p2){
    return abs(p1.first - p2.first) + abs(p1.second - p2.second);
}

template <typename T>
T ceil(T x, T y){
    return (x + y - 1) / y;
}

template<typename T>
T gcd(T a, T b) {
    if(a < 0) a = -a;
    if(b < 0) b = -b;
    if(b == 0) return a;
    else return gcd(b, a % b);
}

ull lcm(ull a, ull b) {
    return a * b / gcd(a, b);
}

string bitseq(long long x){
    string ret = "";
    while(x){
        ret.push_back('0' + (x & 1));
        x <<= 1;
    }
    reverse(ret.begin(), ret.end());
    return ret;
}
#line 2 "code.cpp"

#line 2 "library/Compress.hpp"

/**
 * @brief Compress - 座標圧縮
 */

#line 10 "library/Compress.hpp"
using namespace std;

struct Compress{
    int sz;
    vector<int> to_val;
    map<int, int> to_index;

    /**
     * @brief  配列Vで構築する。
     */
    Compress(vector<int> &V){
        for(auto &v : V){
            to_val.emplace_back(v);
        }
        sort(to_val.begin(), to_val.end());
        auto border = unique(to_val.begin(), to_val.end());
        to_val.erase(border, to_val.end());
        sz = to_val.size();
        for(int i = 0; i < sz; ++i){
            to_index[to_val[i]] = i;
        }
    }

    // 値を対応するインデックスに
    inline int vi(int value){
        return to_index[value];
    }

    // インデックスを対応する値に
    inline int iv(int index){
        return to_val[index];
    }
};
#line 2 "library/Graph/GraphTemplate.hpp"

/**
 * @brief Graph Template - グラフテンプレート
 */

#line 8 "library/Graph/GraphTemplate.hpp"
using namespace std;

using EdgeNum = int;
using Vertex = int;

/**
 * @brief グラフの辺
 */
template<typename CostType = int>
struct Edge{
    Vertex from, to;
    CostType cost;

    Edge(Vertex from, Vertex to, CostType cost) : from(from), to(to), cost(cost){}
};

/**
 * @brief グラフを表すクラス。
 * @note 辺集合によって実現している。
 * @tparam CostType 辺の重みの型。
 */
template<typename CostType = int>
class Graph{
    private:
    int sz;
    bool dir;
    vector<int> indegree;

    public:
    vector<Edge<CostType>> edges;
    vector<vector<EdgeNum>> connect;
    vector<EdgeNum> rev; // 形式上無向グラフでも有向辺を追加するので、辺の追加時に逆辺の辺番号を記録できるようにする
    CostType INF;

    /**
     * @brief Construct a new Graph object
     * @param VertexNum グラフの頂点数
     * @param isDirected 有向グラフとして作成するか
     */
    Graph(int VertexNum, bool isDirected = false) : sz(VertexNum), dir(isDirected), connect(VertexNum), indegree(VertexNum), INF(numeric_limits<CostType>::max()){}

    Graph() = default;

    /**
     * @brief グラフに頂点sと頂点t間の辺を追加する。
     * @note 有向グラフならば頂点sから頂点tへの有向辺を、無向グラフならば頂点sと頂点tを結ぶ無向辺を追加する。
     * @param s 頂点s
     * @param t 頂点t
     * @param w 辺の重み (option, default = 1)
     */
    void add(Vertex s, Vertex t, CostType w = 1){
        assert(0 <= s && s < sz);
        assert(0 <= t && t < sz);
        EdgeNum e = edges.size();
        edges.push_back(Edge<CostType>(s, t, w));
        connect[s].push_back(e);
        ++indegree[t];
        if(!dir){
            edges.push_back(Edge<CostType>(t, s, w));
            connect[t].push_back(e + 1);
            rev.emplace_back(e + 1);
            rev.emplace_back(e);
        }
    }

    /**
     * @brief 指定した辺番号の辺を取得する。
     * @param idx 辺番号
     * @return Edge<CostType> 辺情報
     */
    Edge<CostType> get_edge(EdgeNum idx){
        int e = edges.size();
        assert(0 <= idx && idx < e);
        return edges[idx];
    }

    /**
     * @brief 指定した頂点番号に接続する辺の一覧を取得する。
     * @param v 頂点番号
     * @return vector<Edge<CostType>> 指定した頂点番号に接続する辺の一覧
     */
    vector<Edge<CostType>> get_edges(Vertex v){
        assert(0 <= v && v < sz);
        vector<Edge<CostType>> ret;
        for(auto &idx : connect[v]) ret.push_back(get_edge(idx));
        return ret;
    }

    /**
     * @brief 指定した頂点番号に接続する辺番号の一覧を取得する。
     * @param v 頂点番号
     * @return vector<EdgeNum> 指定した頂点番号に接続する辺番号の一覧
     */
    vector<EdgeNum> get_list(Vertex v){
        assert(0 <= v && v < sz);
        return connect[v];
    }

    /**
     * @brief 逆辺を張ったグラフを作成する。
     * @attention この操作は有向グラフにのみ可能である。
     * @return Graph<CostType> 逆辺を張ったグラフ
     */
    Graph<CostType> reverse(){
        assert(dir);
        Graph<CostType> ret(sz, true);
        for(auto &e : edges){
            ret.add(e.to, e.from, e.cost);
        }
        return ret;
    }

    inline size_t size(){
        return sz;
    }

    inline bool directed(){
        return dir;
    }

    /**
     * @brief ある頂点の次数(出次数)を取得する。
     * @note 有向グラフにおいて、第2引数をtrueにすれば入次数を得ることができる。
     * @param v 頂点番号
     * @param isIn (有向グラフのときのみ有効)入次数を取得するか (option, default = false)
     * @return int 頂点vの指定した値
     */
    inline int degree(Vertex v, bool isIn = false){
        if(dir && isIn) return indegree[v];
        return (int)connect[v].size();
    }

    /**
     * @brief グラフを頂点rootを根とした無向根付き木とみなしたとき、各頂点の親頂点の番号と、それを結ぶ辺番号を取得する。
     * @attention グラフが無向木でない場合の動作は未定義である。
     * @param root 木の根とする頂点番号
     * @return vector<pair<Vertex, EdgeNum>> 各頂点の親の頂点番号と親への辺番号(頂点rootに対してはどちらも-1とする)
     */
    vector<pair<Vertex, EdgeNum>> get_parent(Vertex root){
        vector<pair<Vertex, EdgeNum>> ret(sz, pair<Vertex, EdgeNum>(-1, -1));
        stack<pair<Vertex, Vertex>> st;
        st.emplace(root, -1);
        while(!st.empty()){
            auto [v, parent] = st.top();
            st.pop();
            for(auto &idx : connect[v]){
                if(edges[idx].to == parent) continue;
                ret[edges[idx].to] = pair<Vertex, EdgeNum>(v, rev[idx]);
                st.emplace(edges[idx].to, v);
            }
        }
        return ret;
    }
};
#line 2 "library/Graph/Dijkstra.hpp"

/**
 * @brief Dijkstra - 単一始点最短距離(ダイクストラ法)
 */

#line 9 "library/Graph/Dijkstra.hpp"
using namespace std;

/**
 * @brief  ダイクストラ法で最短距離を求める。
 * @attention グラフに負の重みの辺がない必要がある。
 */
template<typename CostType>
struct Dijkstra{
    private:
    Graph<CostType> &G;
    vector<Vertex> prev_vertex;

    public:
    vector<CostType> dist;

    Dijkstra(Graph<CostType> &G) : G(G), dist(G.size()), prev_vertex(G.size()){}

    /**
     * @brief  頂点sを始点としてダイクストラ法を適用する。
     * @param  s: 始点となる頂点s
     * @note   求められた最短距離はdistに格納される。
     */
    void build(int s){
        dist.assign(G.size(), G.INF);
        prev_vertex.assign(G.size(), -1);
        using p = pair<CostType, Vertex>;
        priority_queue<p, vector<p>, greater<p>> que;
        que.emplace(0, s);
        dist[s] = 0;
        while(!que.empty()){
            auto [d, v] = que.top();
            que.pop();
            if(dist[v] < d) continue;
            for(auto &e : G.get_edges(v)){
                if(d + e.cost < dist[e.to]){
                    dist[e.to] = d + e.cost;
                    prev_vertex[e.to] = v;
                    que.emplace(d + e.cost, e.to);
                }
            }
        }
    }

    /**
     * @brief  頂点sから頂点tへの最短経路を取得する
     * @attention 予めbuildで最短距離を求める必要がある。
     * @param  t: 終点となる頂点t
     * @retval 最短経路
     */
    vector<int> restore(int t){
        vector<int> ret;
        int v = t;
        while(v != -1){
            ret.push_back(v);
            v = prev_vertex[v];
        }
        reverse(ret.begin(), ret.end());
        return ret;
    }
};
#line 6 "code.cpp"

int main(){
    int N, M;
    cin >> N >> M;
    vector<long long> A(M), B(M);
    vector<int> city{1, N};
    for(int i = 0; i < M; ++i){
        cin >> A[i] >> B[i];
        city.emplace_back(A[i]);
        city.emplace_back(B[i]);
    }
    Compress cp(city);
    Graph<long long> G(cp.sz);
    for(int i = 0; i < cp.sz - 1; ++i){
        G.add(i, i + 1, (cp.iv(i + 1) - cp.iv(i)) * 2LL);
    }
    for(int i = 0; i < M; ++i){
        G.add(cp.vi(A[i]), cp.vi(B[i]), 2 * B[i] - 2 * A[i] - 1);
    }
    Dijkstra dk(G);
    dk.build(0);
    cout << dk.dist[cp.sz - 1] << endl;
}
0