結果

問題 No.2337 Equidistant
ユーザー KumaTachiRenKumaTachiRen
提出日時 2023-06-02 21:54:22
言語 C#
(.NET 8.0.203)
結果
AC  
実行時間 2,404 ms / 4,000 ms
コード長 21,045 bytes
コンパイル時間 7,641 ms
コンパイル使用メモリ 142,872 KB
実行使用メモリ 345,144 KB
最終ジャッジ日時 2023-08-28 03:20:26
合計ジャッジ時間 39,128 ms
ジャッジサーバーID
(参考情報)
judge11 / judge14
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 69 ms
26,192 KB
testcase_01 AC 70 ms
28,144 KB
testcase_02 AC 69 ms
26,176 KB
testcase_03 AC 71 ms
26,208 KB
testcase_04 AC 69 ms
26,300 KB
testcase_05 AC 69 ms
26,104 KB
testcase_06 AC 75 ms
27,712 KB
testcase_07 AC 76 ms
29,920 KB
testcase_08 AC 76 ms
27,880 KB
testcase_09 AC 75 ms
27,732 KB
testcase_10 AC 75 ms
27,636 KB
testcase_11 AC 1,422 ms
190,296 KB
testcase_12 AC 1,404 ms
192,560 KB
testcase_13 AC 1,398 ms
188,656 KB
testcase_14 AC 1,390 ms
188,288 KB
testcase_15 AC 1,384 ms
190,340 KB
testcase_16 AC 1,399 ms
190,456 KB
testcase_17 AC 1,371 ms
192,360 KB
testcase_18 AC 1,376 ms
190,272 KB
testcase_19 AC 1,371 ms
190,216 KB
testcase_20 AC 1,349 ms
190,420 KB
testcase_21 AC 1,386 ms
187,008 KB
testcase_22 AC 1,193 ms
204,156 KB
testcase_23 AC 1,195 ms
202,032 KB
testcase_24 AC 2,005 ms
182,048 KB
testcase_25 AC 1,248 ms
202,156 KB
testcase_26 AC 2,404 ms
182,412 KB
testcase_27 AC 1,357 ms
209,624 KB
testcase_28 AC 1,350 ms
345,144 KB
権限があれば一括ダウンロードができます
コンパイルメッセージ
  Determining projects to restore...
  Restored /home/judge/data/code/main.csproj (in 120 ms).
.NET 向け Microsoft (R) Build Engine バージョン 17.0.0-preview-21470-01+cb055d28f
Copyright (C) Microsoft Corporation.All rights reserved.

  プレビュー版の .NET を使用しています。https://aka.ms/dotnet-core-preview をご覧ください
  main -> /home/judge/data/code/bin/Release/net6.0/main.dll
  main -> /home/judge/data/code/bin/Release/net6.0/publish/

ソースコード

diff #

using System;
using System.ComponentModel;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using static Functions;

using ModInt = StaticModInt<Mod998244353>;

static class Program
{
    static public void Main(string[] args)
    {
        Console.SetOut(new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = false });
        new Solver();
        Console.Out.Flush();
    }
}

public class Solver
{
    public Solver()
    {
        Solve();
    }

    struct Op : IReRootingDPOperator<int, int>
    {
        public int SIdentity => 0;
        public int TtoS(int t) => t;
        public int Merge(int x, int y) => x + y;
        public int AddRoot(int i, int j, int x) => x + 1;
    }

    void Solve()
    {
        int n = ri, q = ri;
        var g = new Graph(n);
        var dp = new ReRootingDP<int, int, Op>(n);
        for (int i = 0; i < n - 1; i++)
        {
            int a = ri - 1, b = ri - 1;
            g.AddEdge(a, b);
            dp.AddEdge(a, b);
        }
        var td = new TreeDoubling(g);
        var tj = new TreeJump(g);
        dp.Calc();

        var ans = new List<int>();
        for (int i = 0; i < q; i++)
        {
            int s = ri - 1, t = ri - 1;
            var dist = td.Dist(s, t);
            if (dist % 2 == 1)
            {
                ans.Add(0);
            }
            else
            {
                int c = n;
                int m = tj.Jump(s, t, (int)dist / 2);
                c -= dp[tj.Jump(m, s, 1), m];
                c -= dp[tj.Jump(m, t, 1), m];
                ans.Add(c);
            }
        }
        WriteJoin("\n", ans);
    }

    const long INF = 1L << 60;
    int ri { get { return (int)sc.Integer(); } }
    long rl { get { return sc.Integer(); } }
    ulong rul { get { return sc.UInteger(); } }
    double rd { get { return sc.Double(); } }
    string rs { get { return sc.Scan(); } }
    string rline { get { return sc.Line(); } }
    public StreamScanner sc = new StreamScanner(Console.OpenStandardInput());

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    T[] RepArray<T>(T t, int count) => Enumerable.Repeat(t, count).ToArray();
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    void WriteJoin<T>(string s, IEnumerable<T> t) => Console.WriteLine(string.Join(s, t));
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    void WriteMat<T>(T[,] a)
    {
        int sz1 = a.GetLength(0);
        int sz2 = a.GetLength(1);
        for (int i = 0; i < sz1; i++)
        {
            var s = new List<string>();
            for (int j = 0; j < sz2; j++) s.Add(a[i, j].ToString());
            WriteJoin(" ", s);
        }
    }
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    void Write(object t) => Console.WriteLine(t.ToString());
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    void Write(string str) => Console.WriteLine(str);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    void Write(string str, object arg1) => Console.WriteLine(str, arg1);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    void Write(string str, object arg1, object arg2) => Console.WriteLine(str, arg1, arg2);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    void Write(string str, object arg1, object arg2, object arg3) => Console.WriteLine(str, arg1, arg2, arg3);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    void Write(string str, params object[] arg) => Console.WriteLine(str, arg);
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    void WriteFlush(object t)
    { Console.WriteLine(t.ToString()); Console.Out.Flush(); }
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    void WriteError(object t) => Console.Error.WriteLine(t.ToString());
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    void YN(bool t) => Console.WriteLine(t ? "YES" : "NO");
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    void Yn(bool t) => Console.WriteLine(t ? "Yes" : "No");
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    void yn(bool t) => Console.WriteLine(t ? "yes" : "no");
}

public interface IStaticMod
{
    uint Mod { get; }
    bool IsPrime { get; }
}
public readonly struct Mod1000000007 : IStaticMod
{
    public uint Mod => 1000000007;
    public bool IsPrime => true;
}
public readonly struct Mod998244353 : IStaticMod
{
    public uint Mod => 998244353;
    public bool IsPrime => true;
}
public readonly struct StaticModInt<T> : IEquatable<StaticModInt<T>>, IFormattable where T : struct, IStaticMod
{
    internal readonly uint _v;
    private static readonly T op = default;
    public int Value => (int)_v;
    public static int Mod => (int)op.Mod;
    public static StaticModInt<T> Zero => default;
    public static StaticModInt<T> One => new StaticModInt<T>(1u);
    [MethodImpl(256)]
    public static StaticModInt<T> Raw(int v)
    {
        var u = unchecked((uint)v);
        return new StaticModInt<T>(u);
    }
    [MethodImpl(256)]
    public StaticModInt(long v) : this(Round(v)) { }
    [MethodImpl(256)]
    public StaticModInt(ulong v) : this((uint)(v % op.Mod)) { }
    [MethodImpl(256)]
    private StaticModInt(uint v) => _v = v;
    [MethodImpl(256)]
    private static uint Round(long v)
    {
        var x = v % op.Mod;
        if (x < 0) x += op.Mod;
        return (uint)x;
    }
    [MethodImpl(256)]
    public static StaticModInt<T> operator ++(StaticModInt<T> v)
    {
        var x = v._v + 1;
        if (x == op.Mod) x = 0;
        return new StaticModInt<T>(x);
    }
    [MethodImpl(256)]
    public static StaticModInt<T> operator --(StaticModInt<T> v)
    {
        var x = v._v;
        if (x == 0) x = op.Mod;
        return new StaticModInt<T>(x - 1);
    }
    [MethodImpl(256)]
    public static StaticModInt<T> operator +(StaticModInt<T> lhs, StaticModInt<T> rhs)
    {
        var v = lhs._v + rhs._v;
        if (v >= op.Mod) v -= op.Mod;
        return new StaticModInt<T>(v);
    }
    [MethodImpl(256)]
    public static StaticModInt<T> operator -(StaticModInt<T> lhs, StaticModInt<T> rhs)
    {
        unchecked
        {
            var v = lhs._v - rhs._v;
            if (v >= op.Mod) v += op.Mod;
            return new StaticModInt<T>(v);
        }
    }
    [MethodImpl(256)]
    public static StaticModInt<T> operator *(StaticModInt<T> lhs, StaticModInt<T> rhs) => new StaticModInt<T>((uint)((ulong)lhs._v * rhs._v % op.Mod));
    [MethodImpl(256)]
    public static StaticModInt<T> operator /(StaticModInt<T> lhs, StaticModInt<T> rhs) => lhs * rhs.Inv();
    [MethodImpl(256)]
    public static StaticModInt<T> operator +(StaticModInt<T> v) => v;
    [MethodImpl(256)]
    public static StaticModInt<T> operator -(StaticModInt<T> v) => new StaticModInt<T>(v._v == 0 ? 0 : op.Mod - v._v);
    [MethodImpl(256)]
    public static bool operator ==(StaticModInt<T> lhs, StaticModInt<T> rhs) => lhs._v == rhs._v;
    [MethodImpl(256)]
    public static bool operator !=(StaticModInt<T> lhs, StaticModInt<T> rhs) => lhs._v != rhs._v;
    [MethodImpl(256)]
    public static implicit operator StaticModInt<T>(int v) => new StaticModInt<T>(v);
    [MethodImpl(256)]
    public static implicit operator StaticModInt<T>(uint v) => new StaticModInt<T>((long)v);
    [MethodImpl(256)]
    public static implicit operator StaticModInt<T>(long v) => new StaticModInt<T>(v);
    [MethodImpl(256)]
    public static implicit operator StaticModInt<T>(ulong v) => new StaticModInt<T>(v);
    [MethodImpl(256)]
    public static implicit operator long(StaticModInt<T> v) => v._v;
    [MethodImpl(256)]
    public static implicit operator ulong(StaticModInt<T> v) => v._v;
    [MethodImpl(256)]
    public StaticModInt<T> Pow(long n)
    {
        var x = this;
        var r = new StaticModInt<T>(1U);
        while (n > 0)
        {
            if ((n & 1) > 0) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    [MethodImpl(256)]
    public StaticModInt<T> Inv()
    {
        var (x, y, g) = ExtGcd(_v, op.Mod);
        return new StaticModInt<T>(x);
    }
    [MethodImpl(256)]
    static (long x, long y, long g) ExtGcd(long a, long b)
    {
        if (b == 0) return a >= 0 ? (1, 0, a) : (-1, 0, -a);
        long c = SafeMod(a, b);
        var (x2, y2, g) = ExtGcd(b, c);
        long x = SafeMod(y2, b);
        long y = (g - a * x) / b;
        return (x, y, g);
    }
    [MethodImpl(256)]
    static long SafeMod(long x, long m)
    {
        long r = x % m;
        if (r < 0) r += m;
        return r;
    }
    [MethodImpl(256)]
    public override string ToString() => _v.ToString();
    [MethodImpl(256)]
    public string ToString(string format, IFormatProvider formatProvider) => _v.ToString(format, formatProvider);
    [MethodImpl(256)]
    public override bool Equals(object obj) => obj is StaticModInt<T> m && Equals(m);
    [MethodImpl(256)]
    public bool Equals(StaticModInt<T> other) => _v == other._v;
    [MethodImpl(256)]
    public override int GetHashCode() => _v.GetHashCode();
}

public static class Functions
{
    public static int Popcount(ulong x)
    {
        x = (x & 0x5555555555555555UL) + ((x >> 1) & 0x5555555555555555UL);
        x = (x & 0x3333333333333333UL) + ((x >> 2) & 0x3333333333333333UL);
        x = (x & 0x0f0f0f0f0f0f0f0fUL) + ((x >> 4) & 0x0f0f0f0f0f0f0f0fUL);
        x = (x & 0x00ff00ff00ff00ffUL) + ((x >> 8) & 0x00ff00ff00ff00ffUL);
        x = (x & 0x0000ffff0000ffffUL) + ((x >> 16) & 0x0000ffff0000ffffUL);
        x = (x & 0x00000000ffffffffUL) + ((x >> 32) & 0x00000000ffffffffUL);
        return (int)x;
    }
    public static int Popcount(int x)
    {
        x = (x & 0x55555555) + ((x >> 1) & 0x55555555);
        x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
        x = (x & 0x0f0f0f0f) + ((x >> 4) & 0x0f0f0f0f);
        x = (x & 0x00ff00ff) + ((x >> 8) & 0x00ff00ff);
        x = (x & 0x0000ffff) + ((x >> 16) & 0x0000ffff);
        return x;
    }
    public static int Ctz(long x)
    {
        if (x == 0) return -1;
        return Popcount((ulong)((x & -x) - 1));
    }
    public static int SafeMod(int x, int m)
    {
        int r = x % m;
        return r < 0 ? r + m : r;
    }
    public static long SafeMod(long x, long m)
    {
        long r = x % m;
        return r < 0 ? r + m : r;
    }
    [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Sign(long x) => x == 0 ? 0 : (x < 0 ? -1 : 1);
    [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int DigitSum(long n, int d = 10) { long s = 0; while (n > 0) { s += n % d; n /= d; } return (int)s; }
    [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Floor(long a, long b) => a >= 0 ? a / b : (a + 1) / b - 1;
    [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Ceil(long a, long b) => a > 0 ? (a - 1) / b + 1 : a / b;
    [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Gcd(int a, int b) => b == 0 ? a : Gcd(b, a % b);
    [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Gcd(long a, long b) => b == 0 ? a : Gcd(b, a % b);
    [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Swap(ref int x, ref int y) { x ^= y; y ^= x; x ^= y; }
    [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Swap(ref long x, ref long y) { x ^= y; y ^= x; x ^= y; }
    [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Swap<T>(ref T x, ref T y) { T t = y; y = x; x = t; }
    [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T Clamp<T>(T x, T l, T r) where T : IComparable<T> => x.CompareTo(l) <= 0 ? l : (x.CompareTo(r) <= 0 ? x : r);
    [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T Clamp<T>(ref T x, T l, T r) where T : IComparable<T> => x = x.CompareTo(l) <= 0 ? l : (x.CompareTo(r) <= 0 ? x : r);
    [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Chmin<T>(ref T x, T y) where T : IComparable<T> { if (x.CompareTo(y) > 0) x = y; }
    [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Chmax<T>(ref T x, T y) where T : IComparable<T> { if (x.CompareTo(y) < 0) x = y; }
    public static int LowerBound<T>(T[] arr, Func<T, int> comp, int l = -1, int r = -1) => LowerBound<T>(arr.AsSpan<T>(), comp, l, r);
    public static int LowerBound<T>(Span<T> data, Func<T, int> comp, int l = -1, int r = -1)
    {
        if (data.Length == 0) return -1;
        if (l == -1) l = 0;
        if (r == -1) r = data.Length;
        while (l < r)
        {
            int x = (l + r) / 2;
            if (comp(data[x]) < 0) l = x + 1;
            else r = x;
        }
        return l;
    }
}

public class StreamScanner
{
    public StreamScanner(Stream stream) { str = stream; }
    private readonly Stream str;
    private readonly byte[] buf = new byte[1024];
    private int len, ptr;
    public bool isEof = false;
    public bool IsEndOfStream { get { return isEof; } }
    private byte read()
    {
        if (isEof) throw new EndOfStreamException();
        if (ptr >= len)
        {
            ptr = 0;
            if ((len = str.Read(buf, 0, 1024)) <= 0) { isEof = true; return 0; }
        }
        return buf[ptr++];
    }
    public char Char()
    {
        byte b = 0;
        do b = read();
        while (b < 33 || 126 < b);
        return (char)b;
    }
    public string Line()
    {
        var sb = new StringBuilder();
        for (var b = Char(); b != 10 && !isEof; b = (char)read()) sb.Append(b);
        return sb.ToString();
    }
    public string Scan()
    {
        var sb = new StringBuilder();
        for (var b = Char(); b >= 33 && b <= 126; b = (char)read()) sb.Append(b);
        return sb.ToString();
    }
    public long Integer()
    {
        long ret = 0; byte b = 0; var ng = false;
        do b = read();
        while (b != '-' && (b < '0' || '9' < b));
        if (b == '-') { ng = true; b = read(); }
        for (; true; b = read())
        {
            if (b < '0' || '9' < b) return ng ? -ret : ret;
            else ret = ret * 10 + b - '0';
        }
    }
    public ulong UInteger()
    {
        ulong ret = 0; byte b = 0;
        do b = read();
        while (b < '0' || '9' < b);
        for (; true; b = read())
        {
            if (b < '0' || '9' < b) return ret;
            else ret = ret * 10 + b - '0';
        }
    }
    public double Double() { return double.Parse(Scan()); }
}

class Graph
{
    public struct Edge
    {
        public int src, to;
        public long cost;
        public Edge(int _src, int _to, long _cost)
        {
            src = _src;
            to = _to;
            cost = _cost;
        }
        public Edge(int _to, long _cost)
        {
            src = -1;
            to = _to;
            cost = _cost;
        }
    }
    int n;
    public int Size => n;
    public List<Edge>[] e;
    public Graph(List<int>[] _g)
    {
        n = _g.Length;
        e = new List<Edge>[n];
        for (int i = 0; i < n; i++) e[i] = new List<Edge>();
        for (int i = 0; i < n; i++)
            foreach (var j in _g[i])
                e[i].Add(new Edge(i, j, 1));
    }
    public Graph(int _n)
    {
        n = _n;
        e = new List<Edge>[n];
        for (int i = 0; i < n; i++) e[i] = new List<Edge>();
    }
    public void AddEdge(int x, int y, long cost = 1)
    {
        e[x].Add(new Edge(x, y, cost));
        e[y].Add(new Edge(y, x, cost));
    }
    public void AddDirectedEdge(int src, int to, long cost = 1)
    {
        e[src].Add(new Edge(src, to, cost));
    }
}

interface IReRootingDPOperator<T, S>
{

    S SIdentity { get; }

    S TtoS(T t);

    S Merge(S x, S y);

    T AddRoot(int i, int j, S x);
}

class ReRootingDP<T, S, Op> where Op : IReRootingDPOperator<T, S>
{
    int n;
    Op op = default;
    List<int>[] edges;
    T[] ans;
    Dictionary<int, T>[] dp;

    public T this[int i, int j] { get => dp[i][j]; }
    public T this[int i] { get => ans[i]; }

    public ReRootingDP(int _n)
    {
        n = _n;
        edges = new List<int>[n];
        for (int i = 0; i < n; i++) edges[i] = new List<int>();
    }
    public void AddEdge(int u, int v)
    {
        edges[u].Add(v);
        edges[v].Add(u);
    }

    public void Calc()
    {
        dp = new Dictionary<int, T>[n];
        for (int i = 0; i < n; i++) dp[i] = new Dictionary<int, T>();
        seen = new bool[n];
        for (int i = 0; i < n; i++) if (!seen[i]) DFS1(i);
        seen = new bool[n];
        for (int i = 0; i < n; i++) if (!seen[i]) DFS2(i);
        ans = new T[n];
        for (int i = 0; i < n; i++) ans[i] = dp[i][-1];
    }
    bool[] seen;
    private void DFS1(int x, int p = -1)
    {
        seen[x] = true;
        S val = op.SIdentity;
        foreach (var y in edges[x])
        {
            if (y == p) continue;
            DFS1(y, x);
            val = op.Merge(val, op.TtoS(dp[y][x]));
        }
        dp[x].Add(p, op.AddRoot(x, p, val));
    }
    private void DFS2(int x, int p = -1)
    {
        seen[x] = true;
        int deg = edges[x].Count;
        var dp_r = new S[deg + 1];
        dp_r[deg] = op.SIdentity;
        for (int i = deg - 1; i >= 0; i--) dp_r[i] = op.Merge(dp_r[i + 1], op.TtoS(dp[edges[x][i]][x]));
        if (p != -1) dp[x].Add(-1, op.AddRoot(x, -1, dp_r[0]));
        S sum_l = op.SIdentity;
        for (int i = 0; i < deg; i++)
        {
            int y = edges[x][i];
            if (y != p)
            {
                dp[x].Add(y, op.AddRoot(x, y, op.Merge(sum_l, dp_r[i + 1])));
                DFS2(y, x);
            }
            sum_l = op.Merge(sum_l, op.TtoS(dp[edges[x][i]][x]));
        }
    }
}

class TreeDoubling
{
    int n, log, root;
    int[] depth;
    long[] dist;
    int[,] par;
    public TreeDoubling(in Graph g, int _root = 0)
    {
        n = g.Size;
        root = _root;
        while ((1 << log) < n) log++;
        if (log <= 0) log = 1;
        depth = new int[n];
        dist = new long[n];
        par = new int[n, log];
        for (int i = 0; i < n; i++)
            for (int j = 0; j < log; j++)
                par[i, j] = -1;

        var st = new Stack<int>();
        st.Push(root);
        while (st.Count > 0)
        {
            int x = st.Pop();
            for (int j = 0; j < log - 1 && par[x, j] > -1; j++) par[x, j + 1] = par[par[x, j], j];
            foreach (var y in g.e[x])
            {
                if (y.to == par[x, 0]) continue;
                depth[y.to] = depth[x] + 1;
                dist[y.to] = dist[x] + y.cost;
                par[y.to, 0] = x;
                st.Push(y.to);
            }
        }
    }
    [MethodImpl(256)]
    public int LCA(int x, int y)
    {
        if (depth[x] > depth[y]) { x ^= y; y ^= x; x ^= y; }
        int diff = depth[y] - depth[x];
        for (int i = 0; diff > 0; i++)
        {
            if ((diff & 1) == 1) y = par[y, i];
            diff >>= 1;
        }
        if (x == y) return x;
        for (int i = log - 1; i >= 0; i--)
        {
            if (par[x, i] != par[y, i])
            {
                x = par[x, i];
                y = par[y, i];
            }
        }
        return par[x, 0];
    }
    [MethodImpl(256)]
    public long Dist(int x) => dist[x];
    [MethodImpl(256)]
    public long Dist(int x, int y) => dist[x] + dist[y] - 2 * dist[LCA(x, y)];
    [MethodImpl(256)]
    public bool OnPath(int x, int y, int a) => Dist(x, a) + Dist(a, y) == Dist(x, y);
    [MethodImpl(256)]
    public int Ancestor(int x, int k = 1)
    {
        if (depth[x] < k) return -1;
        for (int i = 0; i < log; i++) if (((k >> i) & 1) == 1) x = par[x, i];
        return x;
    }
}

class TreeJump
{
    int n, u, v;
    TreeDoubling du, dv;
    public TreeJump(in Graph g)
    {
        n = g.Size;
        u = 0;
        v = 0;
        var qu = new Queue<(int x, int p)>();
        qu.Enqueue((0, -1));
        while (qu.Count > 0)
        {
            var x = qu.Dequeue();
            foreach (var e in g.e[x.x]) if (x.p != e.to) qu.Enqueue((e.to, x.x));
            if (qu.Count == 0) u = x.x;
        }
        qu.Enqueue((u, -1));
        while (qu.Count > 0)
        {
            var x = qu.Dequeue();
            foreach (var e in g.e[x.x]) if (x.p != e.to) qu.Enqueue((e.to, x.x));
            if (qu.Count == 0) v = x.x;
        }
        du = new TreeDoubling(g, u);
        dv = new TreeDoubling(g, v);
    }
    [MethodImpl(256)]
    public int Jump(int x, int k)
    {
        if (du.Dist(x) >= k) return du.Ancestor(x, k);
        if (dv.Dist(x) >= k) return dv.Ancestor(x, k);
        return -1;
    }
    [MethodImpl(256)]
    public int Jump(int x, int y, int k)
    {
        var d = du.Dist(x, y);
        if (d < k) return -1;
        return du.Dist(x, du.LCA(x, y)) >= k ? du.Ancestor(x, k) : du.Ancestor(y, (int)d - k);
    }
}
0