#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define MAXN (100005)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
ll N,S,Q,E;
ll shop[MAXN];
vector<pair<ll,ll> > v[MAXN];
ll sub[MAXN];
ll par[MAXN];
ll lvl[MAXN];
ll dist[MAXN][20]; //each node has at most 20 ancestors (dist[i][k] represents the distance between node i and its ancestor with lvl = k [i.e. the (lvl[i] - k)th ancestor of node i]
ll dfs1(ll x,ll p,ll l){
sub[x] = 1;
for(auto u : v[x]){
if(u.first != p && lvl[u.first] == -1){ //unvisited
sub[x] += dfs1(u.first,x,l);
}
}
return sub[x];
}
ll dfs2(ll x,ll p,ll siz){ //siz is total size of this centroid tree
for(auto u : v[x]){
if(u.first != p && lvl[u.first] == -1 && sub[u.first] > siz / 2){
return dfs2(u.first,x,siz); //remember that siz remains constant
}
}
return x;
}
void dfsdist(ll x,ll p,ll curlvl,ll curdist){
dist[x][curlvl] = curdist;
for(auto u : v[x]){
if(u.first != p && lvl[u.first] == -1){ //unvisited
dfsdist(u.first,x,curlvl,curdist + u.second);
//Note: curlvl is unchanged since we are moving down so
//the relative lvl has already changed
}
}
}
void build(ll x,ll p,ll l){
ll siz = dfs1(x,p,l);
ll cent = dfs2(x,p,siz);
if(p == -1) p = cent;
par[cent] = p;
lvl[cent] = l;
dfsdist(cent,-1,l,0);
for(auto u : v[cent]){
if(lvl[u.first] == -1){ //unvisited
build(u.first,cent,l + 1);
}
}
}
ll pre[MAXN], post[MAXN], distfromroot[MAXN];
ll cnt = 0;
void dfsprepost(ll x,ll p){
pre[x] = cnt++;
for(auto u : v[x]){
if(u.first != p){
distfromroot[u.first] = distfromroot[x] + u.second;
dfsprepost(u.first,x);
}
}
post[x] = cnt - 1;
}
struct node{
ll s,e,m,v;
node *l, *r;
node(ll _s,ll _e){
s = _s;
e = _e;
m = (s + e) / 2;
v = 1e18;
if(s != e){
l = new node(s,m);
r = new node(m + 1,e);
}
}
void update(ll x,ll nval){
if(s == e){
v = nval;
}else{
if(x > m) r -> update(x,nval);
else l -> update(x,nval);
v = min(l->v,r->v);
}
}
ll rminq(ll x,ll y){
if(s == x && e == y){
return v;
}else{
if(x > m) return r->rminq(x,y);
else if(y <= m) return l->rminq(x,y);
else return min(l->rminq(x,m),r->rminq(m + 1,y));
}
}
} *root[MAXN];
int main(){
ios_base::sync_with_stdio(false);cin.tie(0);
cin>>N>>S>>Q>>E;
E--;
vector<pair<pair<ll,ll>,ll> > edges;
for(ll i = 0;i < N - 1;i++){
ll a,b,c;
cin>>a>>b>>c;
a--, b--;
v[a].push_back({b,c});
v[b].push_back({a,c});
edges.push_back({{a,b},c});
}
for(ll i = 0;i < S;i++){
cin>>shop[i];
shop[i]--;
}
for(ll i = 0;i < MAXN;i++){
for(ll j = 0;j < 20;j++){
dist[i][j] = 1e18;
}
}
memset(lvl,-1,sizeof(lvl)); //need lvl to find dist[i][lvl]
build(0,-1,0);
dfsprepost(0,-1);
ll ans[Q];
for(ll q = 0;q < Q;q++){
ans[q] = 1e18;
}
vector<pair<ll,ll> > ancestorof[N]; //node i is the ancestor of (pre[j],dist between nodes i and j)
for(ll i = 0;i < N;i++){
ll curlevel = lvl[i];
ll curnode = i;
while(curlevel >= 0){
ancestorof[curnode].push_back({pre[i],dist[i][curlevel]});
curnode = par[curnode];
curlevel--;
}
}
for(ll i = 0;i < N;i++){
sort(ancestorof[i].begin(),ancestorof[i].end()); //to faciliate the lower_bounds later on
}
for(ll i = 0;i < N;i++){
if(!ancestorof[i].empty()){
root[i] = new node(0,ancestorof[i].size() - 1); //Note that we do not need lazy create as the total size of all N segment trees combined will definitely be <= NlogN (since each node contributes at most logN times since each node has at most logN ancestors)
}
}
for(ll i = 0;i < S;i++){
ll curlevel = lvl[shop[i]];
ll curnode = shop[i];
while(curlevel >= 0){
auto it = lower_bound(ancestorof[curnode].begin(),ancestorof[curnode].end(),make_pair(pre[shop[i]],dist[shop[i]][curlevel]));
if(it != ancestorof[curnode].end()){
ll pos = it - ancestorof[curnode].begin();
root[curnode] -> update(pos,dist[shop[i]][curlevel]);
}
curnode = par[curnode];
curlevel--;
}
}
for(ll q = 0;q < Q;q++){
ll edgeind,friendnode;
cin>>edgeind>>friendnode;
edgeind--, friendnode--;
ll A = edges[edgeind].first.first;
ll B = edges[edgeind].first.second;
ll C = edges[edgeind].second;
if(distfromroot[A] > distfromroot[B]) swap(A,B); //B is the deeper node, block B's subtree
bool friendnodeinsidesubtree = false;
bool Exitinsidesubtree = false;
if(pre[B] <= pre[friendnode] && pre[friendnode] <= post[B]){
friendnodeinsidesubtree = true;
}
if(pre[B] <= pre[E] && pre[E] <= post[B]){
Exitinsidesubtree = true;
}
if(friendnodeinsidesubtree && Exitinsidesubtree){ //both E and friendnode are inside that blocked subtree, can reach each other
ans[q] = -1;
continue;
}else if(!friendnodeinsidesubtree && !Exitinsidesubtree){ //both E and friendnode are not inside that blocked subtree, can reach each other
ans[q] = -1;
continue;
}
if(pre[B] <= pre[friendnode] && pre[friendnode] <= post[B]){ //Case 1: the friend is living inside the blocked subtree so he is trapped inside that subtree
ll L = pre[B];
ll R = post[B];
ll curlevel = lvl[friendnode];
ll curnode = friendnode;
while(curlevel >= 0){
auto Lit = lower_bound(ancestorof[curnode].begin(),ancestorof[curnode].end(),make_pair(L,-1ll));
auto Rit = lower_bound(ancestorof[curnode].begin(),ancestorof[curnode].end(),make_pair(R + 1,-1ll));
if(Lit != ancestorof[curnode].end() && Rit != ancestorof[curnode].begin()){
Rit--;
ll Lpos = Lit - ancestorof[curnode].begin();
ll Rpos = Rit - ancestorof[curnode].begin();
ll add = root[curnode] -> rminq(Lpos,Rpos);
ans[q] = min(ans[q],add + dist[friendnode][curlevel]);
}
curnode = par[curnode];
curlevel--;
}
}else{ //Case 2: the friend is living outside the blocked subtree so he cannot enter that subtree
if(pre[B] - 1 >= 0){ //handle prefix [0,pre[B] - 1]
ll X = pre[B] - 1;
ll curlevel = lvl[friendnode];
ll curnode = friendnode;
while(curlevel >= 0){
auto Rit = lower_bound(ancestorof[curnode].begin(),ancestorof[curnode].end(),make_pair(X + 1,-1ll));
if(Rit != ancestorof[curnode].begin()){
Rit--;
ll Rpos = Rit - ancestorof[curnode].begin();
ll add = root[curnode] -> rminq(0,Rpos);
ans[q] = min(ans[q],add + dist[friendnode][curlevel]);
}
curnode = par[curnode];
curlevel--;
}
}
if(post[B] + 1 <= N - 1){ //handle suffix [post[B] + 1,N - 1]
ll X = post[B] + 1;
ll curlevel = lvl[friendnode];
ll curnode = friendnode;
while(curlevel >= 0){
auto Lit = lower_bound(ancestorof[curnode].begin(),ancestorof[curnode].end(),make_pair(X,-1ll));
if(Lit != ancestorof[curnode].end()){
ll Lpos = Lit - ancestorof[curnode].begin();
ll add = root[curnode] -> rminq(Lpos,ancestorof[curnode].size() - 1);
ans[q] = min(ans[q],add + dist[friendnode][curlevel]);
}
curnode = par[curnode];
curlevel--;
}
}
}
}
for(ll q = 0;q < Q;q++){
if(ans[q] == -1){
cout<<"escaped"<<'\n';
}else if(ans[q] == 1e18){
cout<<"oo"<<'\n';
}else{
cout<<ans[q]<<'\n';
}
}
}
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |