Language: C++

#include <iostream>
#include <iomanip>
#include <algorithm>
#include <array>
#include <cassert>
#include <utility>
#include <vector>
#include <optional>
#include <atcoder/all>

template <class InputIterator>
std::ostream& range_output(std::ostream& os_arg, InputIterator first_arg, InputIterator last_arg){ if(first_arg != last_arg){ do{ os_arg << *(first_arg++); if(first_arg == last_arg) break; os_arg << ' '; } while(true); }  return os_arg; }
template <class Tp> std::ostream& operator << (std::ostream& os_arg, const std::vector<Tp>& arr_arg){ return range_output(os_arg, arr_arg.cbegin(), arr_arg.cend()); }
template <class Tp, std::size_t Size> std::ostream& operator << (std::ostream& os_arg, const std::array<Tp, Size>& arr_arg){ return range_output(os_arg, arr_arg.cbegin(), arr_arg.cend()); }
template <class S, class T> std::ostream& operator << (std::ostream& os_arg, const std::pair<S, T>& pair_arg){ return os_arg << '(' << pair_arg.first << ", " << pair_arg.second << ')'; }

#ifndef ONLINE_JUDGE
    template <typename Head> void dump_out(Head head_arg){ std::cerr << head_arg << '\n'; }
    template <typename Head, typename... Tail>
    void dump_out(Head head_arg, Tail... tail_args){ std::cerr << head_arg << ", "; dump_out(tail_args...); }
    #define dump(...) do { std::cerr << "[in line " << __LINE__ << "] " << #__VA_ARGS__ << " : "; dump_out(__VA_ARGS__); } while(false)
#else
    #define dump(...) (void(0))
#endif


// @ ダブリングを行うクラス : 空間 O(N \logN )
//    --> build を忘れるな！！！！
//
//  @ テンプレート第一引数 : 要素の型, 第二引数 : 演算のポインタ
//     (要件) : 演算 merge_f は element_t 上の 半群の演算となること ; つまり, 結合律が成立すること
//  @ 使用方法 : 
//     各頂点 i から 頂点 next[i] に 重み value[i] の辺が張られているとする. (これを, コンストラクタ または直接代入)
//          ====> build で 前計算 (時間 O(NlogN))
//     このとき, 頂点 i から k ステップまでの移動したときの移動先とその辺の畳み込み和を
//     時間計算量 O(logk) 回 で求める (ただし, k < 2^{depth + 1]})
template <class element_t, 
                element_t(*merge_f)(const element_t&, const element_t&),
          class Allocator_ele_t = std::allocator<element_t>,
          class Allocator_int_t = std::allocator<int>
>
class Doubling {
private:
    const int arr_len;               //  配列の長さ (頂点の数)
    const int depth;                 //  前計算の深さ : 2^depth まで計算
    Allocator_int_t     alloc_int;   //  int用のallocator
    Allocator_ele_t     alloc_ele;   //  element_t用のアロケータ
    int* const          next;        // " par[i][k] := 頂点 i から 2^k 回移動した後にいる頂点 " を 1次元配列に直したもの(の先頭ポインタ)
    element_t* const    value;       // " val[i][k] := 頂点 i から 2^k 回移動するの時の畳み込み和" を 1次元配列に直したもの

    // 2進数で x の下から何桁0が続いているかを返す
    static int tail_leading_zeros(long long int x){
        #ifdef __has_builtin
            return __builtin_ctzll(x);
        #else
            int res = 0;
            if((x << 32) == 0) res += 32; else x <<= 32;
            if((x << 16) == 0) res += 16; else x <<= 16;
            if((x <<  8) == 0) res +=  8; else x <<=  8;
            if((x <<  4) == 0) res +=  4; else x <<=  4;
            if((x <<  2) == 0) res +=  2; else x <<=  2;
            if((x <<  1) == 0) res +=  1; else x <<=  1;
            return res;
        #endif
    }
public:
    // @ コンストラクタ by size : 代入後にbuildを使うこと
    Doubling(const int n, const int depth): arr_len(n), depth(depth),
                                            alloc_int(), alloc_ele(),
                                            next( alloc_int.allocate(arr_len * (depth + 1))),
                                            value(alloc_ele.allocate(arr_len * (depth + 1))) {                                        
    }
    // @ コンストラクタ by vector
    template <class Integer, class Element>
    Doubling(const std::vector<Integer>& to, 
             const std::vector<Element>& weight, const int depth): 
                                            arr_len(to.size()), depth(depth), 
                                            alloc_int(), alloc_ele(),
                                            next( alloc_int.allocate(arr_len * (depth + 1))),
                                            value(alloc_ele.allocate(arr_len * (depth + 1))) {
        assert(to.size() == weight.size());
        std::copy(to.cbegin(), to.cend(), next);
        std::copy(weight.cbegin(), weight.cend(), value);
        build();
    }

    // ====================  前処理関係 ===========================
    // @ 各頂点 i から出ている有向辺の行き先を表す next に(配列の長さの分)代入する関数 ; 引数はイテレータの先頭要素
    template <class InputIterator> void assign_next(InputIterator first){ std::copy(first, arr_len, next); }

    // @ 各頂点 i から出ている有向辺の重みを表す value に(配列の長さの分)代入する関数 ; 引数はイテレータの先頭要素
    template <class InputIterator> void assign_value(InputIterator first){ std::copy_n(first, arr_len, value); }
    
    // @ 頂点 from から 頂点 to に重み weight の有向辺を貼る関数 : 0-indexed O(1)
    void assign_at(int from, int to, const element_t& weight){ next[from] = to; value[from] = weight; }

    // @ value, next の　[0, arr_len) の部分の値が定まってる(グラフが定まっている)として前計算を行う : O(NlogN)
    void build(void){
        for(int d = 0, head_prv = 0, head_nxt = arr_len; d < depth; ++d, head_prv += arr_len, head_nxt += arr_len){
            for(int i = 0; i < arr_len; ++i){
                next[head_nxt + i] = next[head_prv + next[head_prv + i]];
                value[head_nxt + i] = merge_f(value[head_prv + i], value[head_prv + next[head_prv + i]] );
            }
        }
    }

    // ==================== クエリ関係 ==================
    // @ 各頂点 i から 2^k 回辺を移動した時の畳み込み和を返す関数
    //  (頂点 i から e1 -> e2 -> ... -> e_2^k のとき (e1.weight op e2.weight op ... op e_2^k.weight))
    std::vector<int> level_k_vertex(const int k){
        assert(0 <= k and k <= depth);
        return std::vector<int>(value + arr_len * k, value + arr_len * (k + 1));
    }

    // @ 各頂点 i から 2^k 回辺を移動した時の畳み込み和を返す関数
    //  (頂点 i から e1 -> e2 -> ... -> e_2^k のとき (e1.weight op e2.weight op ... op e_2^k.weight))
    std::vector<element_t> level_k_elements(const int k){
        assert(0 <= k and k <= depth);
        return std::vector<element_t>(value + arr_len * k, value + arr_len * (k + 1));
    }

    // @ k 回移動した場合の重みの畳み込み和を求める : O(log k)
    //   <注意> 1, k == 0 の時は空が返り値
    //         2, k < 2^{depth + 1} であること
    std::optional<element_t> k_move_elements(int v, long long int k) {
        if(k == 0) return std::nullopt;
        assert((k >> (depth + 1)) == 0 and 0 <= v and v < arr_len);
        const int t = tail_leading_zeros(k); k >>= t;
        int head_pos = arr_len * t;
        element_t res = value[head_pos + v]; v = next[head_pos + v]; k /= 2; head_pos += arr_len;
        for(; k > 0; head_pos += arr_len, k /= 2) if(k % 2 == 1){ res = merge_f(res, value[head_pos + v]); v = next[head_pos + v]; }
        return res;
    }

    // @ k 回移動した場合の 到達箇所 を求める : O(log k)
    //   <注意> 1, k == 0 の時は空が返り値
    //         2, k < 2^{depth + 1} であること
    int k_move_vertex(int v, long long int k) {
        if(k == 0) return v;
        assert((k >> (depth + 1)) == 0 and 0 <= v and v < arr_len);
        const int t = tail_leading_zeros(k); k >>= t;
        int head_pos = arr_len * t;
        v = next[head_pos + v]; k /= 2; head_pos += arr_len;
        for(; k > 0; head_pos += arr_len, k /= 2) if(k % 2 == 1) v = next[head_pos + v];
        return v;
    }
    // @ k 回移動した場合の {到達箇所, 重みの畳み込み和} を求める : O(log k)
    //   <注意> 1, k == 0 の時は空が返り値
    //         2, k < 2^{depth + 1} であること
    std::pair<int, std::optional<element_t>> k_move_datum(int v, long long int k) {
        if(k == 0) return std::pair<int, std::optional<element_t>>(v, std::nullopt);
        assert((k >> (depth + 1)) == 0 and 0 <= v and v < arr_len);
        const int t = tail_leading_zeros(k); k >>= t;
        int head_pos = arr_len * t;
        element_t res = value[head_pos + v]; v = next[head_pos + v]; k /= 2; head_pos += arr_len;
        for(; k > 0; head_pos += arr_len, k /= 2) if(k % 2 == 1){ res = merge_f(res, value[head_pos + v]); v = next[head_pos + v]; }
        return std::pair<int, std::optional<element_t>>(v, res);
    }

    // @ 頂点 v (0-indexed) から出発して 初めて Compare_t()(移動辺の重みの畳み込み和, val) が
    //    false となるような 最短移動の 「(到達頂点, 移動回数) を返す」関数 : 二分探索 O(log N)
    //  * ただし, 比較関数が単調 (true, true, true, ..., true, false, false, ...) であることを仮定する.
    //  ※ !!!!!!!!!!! 前計算の時のオーバーフローに注意 !!!!!!!!!!!!
    template <class Compare_t = std::less<element_t>>
    std::pair<int, long long int> binary_search(int v, const element_t& val){
        if(not Compare_t()(value[v], val)) return std::pair<int, long long int>(v, 0);
        long long int cnt_move = 0;
        std::optional<element_t> the_value = std::nullopt;
        for(int i = depth, head_pos = arr_len * depth; i >= 0; --i, head_pos -= arr_len){
            const element_t next_value = the_value ? merge_f(*the_value, value[head_pos + v]) : value[head_pos + v];
            if(Compare_t()(next_value, val)){ cnt_move |= (1LL << i); v = next[head_pos + v]; the_value = next_value; }
        }
        return std::pair<int, long long int>(v, cnt_move);
    }
};

bool plus(const bool& x, const bool& y){
    return true;
}


int main(void){
    std::cin.tie(nullptr); std::ios_base::sync_with_stdio(false); 
    std::cout << std::fixed << std::setprecision(16);

    int n; long long int k; std::cin >> n >> k;
    Doubling<bool, plus> Db(n, 60);
    for(int i = 0; i < n; ++i){
        int a; std::cin >> a; --a; Db.assign_at(i, a, true);
    } Db.build();
    std::cout << Db.k_move_vertex(0, k) + 1 << '\n';
    
    
    return 0;
}

Compiler output:
a.cc:9:10: fatal error: atcoder/all: No such file or directory
    9 | #include <atcoder/all>
      |          ^~~~~~~~~~~~~
compilation terminated.