제출 #825466

#제출 시각아이디문제언어결과실행 시간메모리
825466Shreyan_PaliwalValley (BOI19_valley)C++17
0 / 100
224 ms25572 KiB
#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;

template<typename T>
string tostr(const T& value) {
    ostringstream oss;
    oss << value;
    return oss.str();
}

template<typename... Args>
string fstr(const string& format, Args... args) {
    string result = format;
    size_t pos = 0;
    size_t argIndex = 0;

    auto replaceArg = [&](const auto& arg) {
        pos = result.find("{}", pos);
        if (pos != string::npos) {
            result.replace(pos, 2, tostr(arg));
            ++argIndex;
        }
    };

    (replaceArg(args), ...);

    return result;
}

/*
 * Keeps mint objects modulo MOD constant
*/

// const int MOD = 1e9 + 7;
// struct mint {
//     int x;

//     mint() { x = 0; }
//     mint(int X) { x = X; }
//     mint(long long X) { x = ((X % MOD) + MOD) % MOD; }
//     mint(unsigned long long X) { x = (X % MOD); }

//     mint pow(int k) { mint r = 1, a = *this; while (k) { if (k & 1) r *= a; a *= a; k >>= 1; } return r; }

//     mint& operator+=(mint o) { if ((x += o.x) >= MOD) x -= MOD; return *this; }
//     mint& operator-=(mint o) { if ((x += MOD - o.x) >= MOD) x -= MOD; return *this; }
//     mint& operator*=(mint o) { x = 1ll * x * o.x % MOD; return *this; }
//     mint& operator/=(mint o) { return (*this) *= o.pow(MOD - 2); }

//     mint operator+(mint o) const { return mint(*this) += o; }
//     mint operator-(mint o) const { return mint(*this) -= o; }
//     mint operator*(mint o) const { return mint(*this) *= o; }
//     mint operator/(mint o) const { return mint(*this) /= o; }

//     bool operator<(mint o) const { return x < o.x; }

//     friend ostream& operator<<(ostream& os, mint a) { os << a.x; return os; }
// };

/*
 * Matrices
 * Multiplication
*/

// typedef vector<vector<int>> MAT;
// struct Matrix {
//     MAT v;
//     Matrix(MAT V) { swap(v, V); }
//     Matrix(int a, int b) { v.resize(a, vector<int>(b, 0)); }
//     Matrix operator*(const Matrix& o) {
//         // assert(v[0].size() == o.v.size());
//         Matrix M(v.size(), o.v[0].size());
//         for (int i = 0; i < v.size(); i++)
//             for (int j = 0; j < o.v[0].size(); j++)
//                 for (int k = 0; k < (int)v[0].size(); k++)
//                     M.v[i][j] += v[i][k] * o.v[k][j];
//         return M;
//     }
//     Matrix operator^(int k) {
//         if (k&1) return (((*this)*(*this))^(k/2))*(*this);
//         else return ((*this)*(*this))^(k/2);
//     }
// };

/*
 * Segment Tree
 * - RANGE QUERY
 * - RANGE UPDATE
*/

// template<class T>
// T identity; // [SET IDENTITY OF CLASS T, hardcode T classname]
// struct ND {
//     ND* ch[2] = { nullptr, nullptr };
//     T v, f;

//     inline void create() {
//         if (!ch[0]) ch[0] = new ND; // [POTENTIALLY UPDATE VALUES]
//         if (!ch[1]) ch[1] = new ND; // [POTENTIALLY UPDATE VALUES]
//     }

//     inline T merge(int l, int r) {
//         // [INSERT CODE FOR MERGE SEGMENT]
//     }

//     inline void push(int l, int r) {
//         create();
//         // [INSERT CODE FOR PUSHING SEGMENT FLAG]
//     }

//     void upd(int l, int r, int L, int R, T K) {
//         push(l, r);
//         if (R < l || r < L) return;
//         if (L <= l && r <= R) {
//             // [INSERT CODE FOR UPDATE SEGMENT]
//             return;
//         }
//         int m = (l + r) >> 1;
//         ch[0]->upd(l, m, L, R, K);
//         ch[1]->upd(m+1, r, L, R, K);
//         merge(l, r);
//     }

//     T qry(int l, int r, int L, int R) {
//         push(l, r);
//         if (R < l || r < L) return identity;
//         if (L <= l && r <= R) return v;
//         int m = (l + r) >> 1;
//         return OPERATION(ch[0]->qry(l,m,L,R), ch[1]->qry(m+1,r,L,R));
//     }

//     ~ND() { delete ch[0]; delete ch[1]; ch[0] = ch[1] = nullptr; }
// };

/*
 * Convex Hull Trick
 * - ORDERED SLOPES
 * - UNORDERED QUERIES O(N log N), ORDERED QUERIES O(N)
*/

// struct F {
//     int a, b;
//     F() {}
//     F(int A, int B) : a(A), b(B){ if (b<0) a*=-1, b*=-1; }
//     bool operator<(F o) const { return a*o.b < b*o.a; }
//     bool operator<=(F o) const { return a*o.b <= b*o.a; }
// };
// struct L {
//     int m, b;
//     int operator()(int x) { return m*x + b; }
//     F operator^(L o) { return F{b-o.b,o.m-m}; }
// };
// struct CHT {
//     vector<L> h;
//     // deque<L> h; // if using SECOND CODE in QRY FUNCTION
//     void add(L l) {
//         // // min hull + decreasing slopes OR max hull + increasing slopes
//         // while (h.size() >= 2 && (h.end()[-2]^l) <= (h.end()[-2]^h.back())) h.pop_back();
//         // h.push_back(l);

//         // // min hull + increasing slopes OR max hull + decreasing slopes
//         // while (h.size() >= 2 && (h.end()[-2]^h.back()) <= (h.end()[-2]^l)) h.pop_back();
//         // h.push_back(l);
//     }
//     int qry(int x) {
//         // O(N log N) time, unordered queries
//         // int lo = 0, hi = h.size()-1;
//         // while (lo < hi) {
//         //     int m = (lo + hi) >> 1;
//         //     if (h[m](x) < h[m+1](x)) // < or > depending on min/max qry
//         //         lo = m+1;
//         //     else 
//         //         hi = m;
//         // }
//         // return h[lo](x);

//         // if need O(N) time, use **DEQUE INSTEAD OF VECTOR** & use code below
//         // while (h.size() >= 2 && h[1](x) < h[0](x)) h.pop_front(); // < or > depending on min/max qry
//         // return h[0](x);
//     }
// };

/*
 * Li Chao Tree 
 * UNORDERED SLOPES, UNORDERED QUERIES O(N log N)
 * Extension of segment tree
*/

// struct F {
//     int a, b;
//     F() {}
//     F(int A, int B) : a(A), b(B){ if (b<0) a*=-1, b*=-1; }
//     bool operator<(F o) const { return a*o.b < b*o.a; }
//     bool operator<=(F o) const { return a*o.b <= b*o.a; }
// };
// struct L {
//     int m, b;
//     int operator()(int x) { return m*x + b; }
//     F operator^(L o) { return F{b-o.b,o.m-m}; }
// };
// // #define OP(a, b) (a < b) // DEFINE OPERATOR
// // #define OPR(a, b) (min(a,b)) // DEFINE OPERATOR
// #define OP(a, b) (a > b)
// #define OPR(a, b) (max(a,b))
// struct ND {
//     ND * ch[2] = { nullptr, nullptr };
//     L v = L{1, 0};
//     void create() {
//         if (!ch[0]) { ch[0] = new ND; ch[0]->v = v; }
//         if (!ch[1]) { ch[1] = new ND; ch[1]->v = v; }
//     }
//     void upd(int l, int r, L V) {
//         // update the li chao tree with line V
//         if (v.m == V.m && v.b == V.b) return;
//         if (l == r) {
//             // if new line is better, swap
//             if (OP(V(l), v(l))) swap(V, v);
//             return;
//         }
//         create();
//         int m = (l + r) >> 1; // midpoint
//         if (OP(V(m), v(m))) swap(V, v); // if new line is better at mid, it has one half, so swap
//         F x = v ^ V; // intersection of two lines
//         if (x <= F(m, 1)) 
//             ch[0]->upd(l, m, V);
//         else
//             ch[1]->upd(m+1, r, V);
//     }
//     int qry(int l, int r, int X) {
//         // qry li chao tree for x coord X        
//         int ret = v(X); // gets value for current segment
//         if (l != r) {
//             int m = (l + r) >> 1;
//             if (X <= m && ch[0] != nullptr) return OPR(ret, ch[0]->qry(l, m, X));
//             if (X > m && ch[1] != nullptr) return OPR(ret, ch[1]->qry(m+1, r, X));
//         }
//         return ret;
//     }
// };
// #undef OP
// #undef OPR

const int maxn = 100000;
const int INF = 2000000000;

int n, s, q, e; // nodes, numshops, numqueries, valleynode
vector<pair<int,int>> adj[maxn];
pair<int,int> edges[maxn];
int shop[maxn]; // is shop?
int closest[maxn]; // closest shop in subtree

int dist[maxn]; // distance to root, set


int dpth[maxn]; // depth from root, set
int bl[maxn][20]; // set
int bld[maxn][20]; // array[nd] = - 2 * dist[nd] + min(dist[shop]) for shop in subtree[dist]


void dfs(int nd, int par, int pardist, int d) {
    // set depth
    dpth[nd] = d;

    // set binary lifting
    bl[nd][0] = par;
    for (int i = 1; i < 20; i++) bl[nd][i] = bl[bl[nd][i-1]][i-1];

    // recurse dfs, set distance from root
    for (auto i : adj[nd])
        if (i.first != par) {
            dist[i.first] = dist[nd] + i.second;    
            dfs(i.first, nd, i.second, d+1);
        }
    
    // init closest shop in subtree
    closest[nd] = shop[nd] ? 0 : INF;   
    for (auto i : adj[nd])
        if (i.first != par)
            closest[nd] = min(closest[nd], i.second + closest[i.first]);

    return;
}

void dfs_bld(int nd) {
    if (closest[nd] == INF) bld[nd][0] = INF;
    else bld[nd][0] = -dist[nd] + closest[nd];
    for (int i = 1; i < 20; i++) bld[nd][i] = min(bld[nd][i-1], bld[bl[nd][i-1]][i-1]);

    for (auto i : adj[nd])
        if (i.first != bl[nd][0])
            dfs_bld(i.first);
}

inline int jmp(int nd, int k) {
    for (int i = 19; i >= 0; i--) if ((k >> i) & 1) nd = bl[nd][i];
    return nd;
}

inline bool on_path(int nd, int nd2) {
    // checking if nd2 is on nd's path to root
    return (dpth[nd] >= dpth[nd2] && jmp(nd, dpth[nd] - dpth[nd2]) == nd2);
}

void solve() {
    cin >> n >> s >> q >> e; e--;
    for (int i = 0; i < n-1; i++) {
        int c; cin >> edges[i].first >> edges[i].second >> c;
        edges[i].first--, edges[i].second--;
        adj[edges[i].first].push_back({edges[i].second, c});
        adj[edges[i].second].push_back({edges[i].first, c});
    }

    for (int i = 0; i < s; i++) { int a; cin >> a; a--; shop[a] = 1; }

    dfs(e, e, 0, 0);
    dfs_bld(e);

    for (int i = 0; i < q; i++) {
        // a is edge removed, b is node to find
        int a, b; cin >> a >> b; a--, b--;

        // check if escape possible
        if (!on_path(b, edges[a].first) || !on_path(b, edges[a].second)) {
            cout << "escaped" << endl;
            continue;
        }

        // not possible, so search
        if (dpth[edges[a].first] < dpth[edges[a].second]) swap(edges[a].first, edges[a].second);
        int val = INF;
        int B = b;
        for (int i = 19; i >= 0; i--) 
            if (((dpth[edges[a].first] - dpth[b] - 1) >> i) & 1)
                val = min(val, bld[b][i]), 
                b = bl[b][i];

        if (val == INF) {
            cout << "oo" << endl;
            continue;
        }

        cout << val + dist[B] << endl;
        continue;
    }

}

signed main() {
    cin.tie(nullptr) -> ios::sync_with_stdio(false);
    // freopen("main.in", "r", stdin);
    int t; 
    // cin >> t;
    t=1;
    while(t--) solve();
    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...