Problem: cf1403_a
Difficulty: medium
Categories: data structures, search
Time limit: 3000 ms, memory limit: 256 MB

Once upon a time, in the Land of the Shamans, everyone lived on the Sky-High Beanstalk. Each shaman had a unique identifying number $i$ between $0$ and $N-1$, and an altitude value $H_i$, representing how high he lived above ground level. The distance between two altitudes is the absolute value of their difference.

All shamans lived together in peace, until one of them stole the formula of the world-famous Potion of Great Power. To cover his/her tracks, the Thief has put a Curse on the land: most inhabitants could no longer trust each other...

Despite the very difficult circumstances, the Order of Good Investigators have gained the following information about the Curse:

* When the Curse first takes effect, everyone stops trusting each other.
* The Curse is unstable: at the end of each day (exactly at midnight), one pair of shamans will start or stop trusting each other.
* Unfortunately, each shaman will only ever trust at most $D$ others at any given time.

They have also reconstructed a log of who trusted whom: for each night they know which pair of shamans started/stopped trusting each other.

They believe the Thief has whispered the formula to an Evil Shaman. To avoid detection, both of them visited the home of one of their (respective) trusted friends. During the visit, the Thief whispered the formula to the Evil Shaman through the window. (Note: this trusted friend did not have to be home at the time. In fact, it's even possible that they visited each other's houses – shamans are weird.)

Fortunately, whispers only travel short distances, so the Order knows the two trusted friends visited (by the Thief and the Evil Shaman) must live very close to each other.

They ask you to help with their investigation. They would like to test their suspicions: what if the Thief was $x$, the Evil Shaman was $y$, and the formula was whispered on day $v$? What is the smallest distance the whispered formula had to travel? That is, what is the minimum distance between the apartments of some shamans $x'$ and $y'$ (i.e. $\min\left(\left|H_{x'} - H_{y'}\right|\right)$), such that $x'$ was a trusted friend of $x$ and $y'$ was a trusted friend of $y$ on day $v$?

They will share all their information with you, then ask you a number of questions. You need to answer each question immediately, before receiving the next one.

Interaction

The interaction will begin with a line containing $N$, $D$, $U$ and $Q$ $(2 \leq N \leq 100000$, $1 \leq D \leq 500$, $0 \leq U \leq 200000$, $1 \leq Q \leq 50000)$ – the number of shamans, the maximum number of trusted friends a shaman can have at any given point, the number of days, and the number of questions.

On the next line $N$ space separated integers will follow, the $i$th $(1\leq i \leq N)$ of which being $H_{i-1}$ $(0\leq H_{i-1} \leq 10^9)$, the altitude of shaman $i-1$.

On the next $U$ lines there will be two integers each, on the $i$th ($1 \leq i \leq U$) $A_i$ and $B_i$ $(0 \leq A_i, B_i < N$ and $A_i \neq B_i)$, which represents a pair of shamans who started or stopped trusting each other at the end of day $i-1$. That is, if $A_i$ and $B_i$ trusted each other on day $i-1$, they did not trust each other on day $i$, or vice versa. Read all of these integers.

The interactor now will ask you $Q$ question, so the following interaction should happen $Q$ times:

1. Read $3$ integers describing the current query: $x,y$ and $v$ ($x \neq y$, $0 \leq x,y < N$ and $0 \leq v \leq U$), where $x$ is the suspected Thief, $y$ is the suspected Evil Shaman, and $v$ is the suspected day..
2. Then print the answer to this query on a single line, i.e. you should print the minimum distance the whispered formula had to travel from some trusted friend $x'$ of $x$ to a trusted friend $y'$ of $y$.
   * In case someone trusted both $x$ and $y$ (i.e. $x'=y'$), you should print $0$.
   * If $x$ or $y$ had no trusted friends, print $10^9$.

After printing each line do not forget to output end of line and flush the output. Otherwise, you will get Idleness limit exceeded. To do this, use:

* fflush(stdout) or cout.flush() in C++;
* System.out.flush() in Java;
* flush(output) in Pascal;
* stdout.flush() in Python;
* see documentation for other languages.

Scoring

 $ \begin{array}{|c|c|c|} \hline \text{Subtask} & \text{Points} & \text{Constraints} \\ \hline 1 & 0 & \text{samples}\\ \hline 2 & 17 & Q,U \leq 1000 \\ \hline 3 & 14 & v=U \: \text{for all questions} \\ \hline 4 & 18 & H_i \in \left\{0,1\right\} \: \text{for all shamans} \: i \\ \hline 5 & 21 & U,N \leq 10000\\ \hline 6 & 30 & \text{no additional constraints}\\ \hline \end{array} $

Example

Input

```
6 5 11 4
2 42 1000 54 68 234
0 1
2 0
3 4
3 5
3 5
1 3
5 3
0 5
3 0
1 3
3 5
0 3 4
3 0 8
0 5 5
3 0 11
```

Output

```
26
0
1000000000
14
```

Note

Example queries: ![](https://espresso.codeforces.com/c1c942c8e50047ce7929e1f2d50a8d18611589c9.png)

Evolution of friendships: ![](https://espresso.codeforces.com/896597d0952437505a39da5fbf78ec2d233360b8.png)

Non-adaptive interactor (C++):
#include "testlib.h"
#include <bits/stdc++.h>
using namespace std;


static long long queries_count = 0;
static long long query_limit = 0;


static void log_metrics() {
    try {
        tout << "queries=" << queries_count << endl;
        tout << "query_limit=" << query_limit << endl;
    } catch (...) {
        
    }
}


static void finish(TResult verdict, const string& msg) {
    log_metrics();
    quitf(verdict, "%s", msg.c_str());
}

struct Query {
    int x, y, v, id;
};

const int INF_DIST = 1000000000;

int main(int argc, char** argv) {
    
    registerInteraction(argc, argv);
    atexit(log_metrics);

    
    int N = inf.readInt(2, 100000, "N");
    int D = inf.readInt(1, 500, "D");
    int U = inf.readInt(0, 200000, "U");
    int Q = inf.readInt(1, 50000, "Q");

    
    query_limit = Q;
    log_metrics(); 

    vector<int> H(N);
    for (int i = 0; i < N; i++) {
        H[i] = inf.readInt(0, 1000000000, format("H[%d]", i));
    }

    vector<pair<int, int>> updates(U);
    for (int i = 0; i < U; i++) {
        updates[i].first = inf.readInt(0, N - 1, format("u_u[%d]", i));
        updates[i].second = inf.readInt(0, N - 1, format("u_v[%d]", i));
    }

    vector<Query> all_queries(Q);
    
    vector<vector<int>> queries_at_time(U + 1);
    for (int i = 0; i < Q; i++) {
        all_queries[i].x = inf.readInt(0, N - 1, format("q_x[%d]", i));
        all_queries[i].y = inf.readInt(0, N - 1, format("q_y[%d]", i));
        all_queries[i].v = inf.readInt(0, U, format("q_v[%d]", i));
        all_queries[i].id = i;
        queries_at_time[all_queries[i].v].push_back(i);
    }

    
    
    
    
    
    
    vector<vector<pair<int, int>>> adj(N);
    vector<long long> expected_answers(Q);

    
    auto toggle_edge = [&](int u, int v) {
        int h_v = H[v];
        pair<int, int> val = {h_v, v};
        
        auto it = lower_bound(adj[u].begin(), adj[u].end(), val);
        if (it != adj[u].end() && it->first == h_v && it->second == v) {
            
            adj[u].erase(it);
        } else {
            
            adj[u].insert(it, val);
        }
    };

    
    for (int t = 0; t <= U; t++) {
        
        
        if (t > 0) {
            int u = updates[t-1].first;
            int v = updates[t-1].second;
            toggle_edge(u, v);
            toggle_edge(v, u);
        }

        
        for (int q_idx : queries_at_time[t]) {
            int x = all_queries[q_idx].x;
            int y = all_queries[q_idx].y;

            const auto& list_x = adj[x];
            const auto& list_y = adj[y];

            if (list_x.empty() || list_y.empty()) {
                expected_answers[q_idx] = INF_DIST;
            } else {
                long long min_dist = 2000000000LL;
                
                size_t i = 0, j = 0;
                while (i < list_x.size() && j < list_y.size()) {
                    long long diff = abs(list_x[i].first - list_y[j].first);
                    if (diff < min_dist) min_dist = diff;
                    
                    if (min_dist == 0) break;

                    if (list_x[i].first < list_y[j].first) {
                        i++;
                    } else {
                        j++;
                    }
                }
                expected_answers[q_idx] = min_dist;
            }
        }
    }

    
    
    cout << N << " " << D << " " << U << " " << Q << endl;
    
    for (int i = 0; i < N; i++) {
        cout << H[i] << (i == N - 1 ? "" : " ");
    }
    cout << endl;

    for (int i = 0; i < U; i++) {
        cout << updates[i].first << " " << updates[i].second << endl;
    }
    cout.flush(); 

    
    for (int i = 0; i < Q; i++) {
        
        cout << all_queries[i].x << " " << all_queries[i].y << " " << all_queries[i].v << endl;
        
        
        long long user_ans;
        if (!(cin >> user_ans)) {
            finish(_pe, "Unexpected end of file or malformed output while waiting for answer to query " + to_string(i + 1));
        }

        
        if (user_ans != expected_answers[i]) {
            finish(_wa, "Wrong answer on query " + to_string(i + 1) + 
                   ": expected " + to_string(expected_answers[i]) + 
                   ", found " + to_string(user_ans));
        }

        queries_count++;
        
        if (queries_count % 100 == 0) log_metrics();
    }

    finish(_ok, "All " + to_string(Q) + " queries correct");
    return 0;
}


Adaptive interactor (C++):
#include "testlib.h"
#include <bits/stdc++.h>

using namespace std;


static int queries_count = 0;
static int query_limit = 0;



static void log_metrics() {
    try {
        tout << "queries=" << queries_count << endl;
        tout << "query_limit=" << query_limit << endl;
    } catch (...) {
        
    }
}


static void finish(TResult verdict, const string& msg) {
    log_metrics();
    quitf(verdict, "%s", msg.c_str());
}


const int MAXN = 100005;
int H[MAXN];
vector<int> adj[MAXN]; 

struct Update {
    int u, v;
};

struct Query {
    int id;
    int x, y, v;
    long long expected_ans;
};





void toggle_edge(int u, int v) {
    auto toggle = [](vector<int>& vec, int val) {
        for (size_t i = 0; i < vec.size(); ++i) {
            if (vec[i] == val) {
                
                vec[i] = vec.back();
                vec.pop_back();
                return;
            }
        }
        
        vec.push_back(val);
    };
    
    toggle(adj[u], v);
    toggle(adj[v], u);
}



long long solve_query(int x, int y) {
    
    if (adj[x].empty() || adj[y].empty()) return 1000000000LL;

    
    static vector<int> hx, hy;
    hx.clear(); hy.clear();
    hx.reserve(adj[x].size());
    hy.reserve(adj[y].size());
    
    for (int n : adj[x]) hx.push_back(H[n]);
    for (int n : adj[y]) hy.push_back(H[n]);
    
    
    sort(hx.begin(), hx.end());
    sort(hy.begin(), hy.end());

    long long min_diff = 2000000000LL;
    size_t i = 0, j = 0;
    while (i < hx.size() && j < hy.size()) {
        long long diff = abs((long long)hx[i] - hy[j]);
        if (diff < min_diff) min_diff = diff;
        if (min_diff == 0) return 0; 
        
        if (hx[i] < hy[j]) i++;
        else j++;
    }
    return min_diff;
}

int main(int argc, char** argv) {
    
    registerInteraction(argc, argv);
    atexit(log_metrics); 

    
    int N = inf.readInt();
    int D = inf.readInt();
    int U = inf.readInt();
    int Q = inf.readInt();
    
    query_limit = Q;
    log_metrics(); 

    
    
    cout << N << " " << D << " " << U << " " << Q << endl;

    for (int i = 0; i < N; ++i) {
        H[i] = inf.readInt();
        if (i > 0) cout << " ";
        cout << H[i];
    }
    cout << endl;

    vector<Update> updates(U);
    for (int i = 0; i < U; ++i) {
        updates[i].u = inf.readInt();
        updates[i].v = inf.readInt();
        
        cout << updates[i].u << " " << updates[i].v << "\n";
    }
    cout.flush(); 

    
    vector<Query> queries(Q);
    for (int i = 0; i < Q; ++i) {
        queries[i].id = i;
        queries[i].x = inf.readInt();
        queries[i].y = inf.readInt();
        queries[i].v = inf.readInt(); 
        queries[i].expected_ans = -1;
    }

    
    
    vector<Query*> query_ptrs(Q);
    for (int i = 0; i < Q; ++i) query_ptrs[i] = &queries[i];
    sort(query_ptrs.begin(), query_ptrs.end(), [](Query* a, Query* b) {
        return a->v < b->v;
    });

    int current_time = 0; 
    for (Query* q : query_ptrs) {
        
        
        while (current_time < q->v) {
            toggle_edge(updates[current_time].u, updates[current_time].v);
            current_time++;
        }
        q->expected_ans = solve_query(q->x, q->y);
    }

    
    
    for (int i = 0; i < Q; ++i) {
        
        if (i > 0 && i % 10 == 0) log_metrics();

        
        cout << queries[i].x << " " << queries[i].y << " " << queries[i].v << endl;
        queries_count++;

        
        long long val;
        if (!(cin >> val)) {
            finish(_pe, "Unexpected EOF or malformed output from contestant");
        }

        
        if (val != queries[i].expected_ans) {
             string msg = "Wrong answer on query " + to_string(i+1) + 
                         " (x=" + to_string(queries[i].x) + 
                         ", y=" + to_string(queries[i].y) + 
                         ", v=" + to_string(queries[i].v) + ")" +
                         ". Expected " + to_string(queries[i].expected_ans) + 
                         ", found " + to_string(val);
             finish(_wa, msg);
        }
    }

    finish(_ok, "All queries correct");
    return 0;
}


Test generator (C++):
#include "testlib.h"
#include <bits/stdc++.h>

using namespace std;

int main(int argc, char* argv[]) {
    registerGen(argc, argv, 1);
    
    
    string mode = opt<string>("mode", "non");
    int seedVal = atoi(argv[1]);

    int N, D, U, Q;
    const int MAX_N = 100000;
    const int MAX_D = 500;
    const int MAX_U = 200000;
    const int MAX_Q = 50000;
    
    
    
    
    
    
    
    
    if (seedVal == 1) { 
        N = rnd.next(5, 20);
        D = rnd.next(2, 5);
        U = rnd.next(5, 20);
        Q = rnd.next(5, 20);
    } 
    else if (seedVal == 2) { 
        N = MAX_N;
        D = 1;
        U = MAX_U;
        Q = MAX_Q;
    } 
    else if (seedVal == 3) { 
        N = MAX_N;
        D = MAX_D;
        U = MAX_U;
        Q = MAX_Q;
    } 
    else if (seedVal == 4) { 
        N = MAX_N;
        D = rnd.next(5, 50);
        U = MAX_U;
        Q = MAX_Q;
    } 
    else if (seedVal == 5) { 
        N = MAX_N;
        D = rnd.next(10, 100);
        U = MAX_U;
        Q = MAX_Q;
    } 
    else { 
        N = rnd.next(MAX_N / 2, MAX_N);
        D = rnd.next(1, MAX_D);
        U = rnd.next(MAX_U / 2, MAX_U);
        Q = rnd.next(MAX_Q / 2, MAX_Q);
    }

    
    cout << N << " " << D << " " << U << " " << Q << "\n";

    
    vector<int> H(N);
    for (int i = 0; i < N; ++i) {
        if (seedVal == 4) H[i] = rnd.next(0, 1);
        else H[i] = rnd.next(0, 1000000000);
    }
    for (int i = 0; i < N; ++i) {
        cout << H[i] << (i == N - 1 ? "" : " ");
    }
    cout << "\n";

    
    vector<vector<int>> adj(N);
    vector<int> deg(N, 0);
    vector<pair<int, int>> existing_edges; 
    
    auto hasEdge = [&](int u, int target) {
        for (int v : adj[u]) if (v == target) return true;
        return false;
    };

    
    for (int i = 0; i < U; ++i) {
        bool op_add;
        
        if (existing_edges.empty()) op_add = true;
        else if (i > U - 1000 && existing_edges.size() < 100) op_add = true; 
        else op_add = (rnd.next(2) == 0);

        int u = -1, v = -1;
        bool success = false;
        
        
        
        auto try_current_op = [&]() -> bool {
            if (op_add) {
                int cu = rnd.next(N);
                if (deg[cu] >= D) return false;
                int cv = rnd.next(N);
                if (cu == cv || deg[cv] >= D) return false;
                if (!hasEdge(cu, cv)) {
                    u = cu; v = cv;
                    return true;
                }
            } else {
                if (existing_edges.empty()) return false;
                int idx = rnd.next(existing_edges.size());
                u = existing_edges[idx].first;
                v = existing_edges[idx].second;
                
                existing_edges[idx] = existing_edges.back();
                existing_edges.pop_back();
                return true;
            }
            return false;
        };

        
        for (int k = 0; k < 20; ++k) {
            if (try_current_op()) { success = true; break; }
        }
        
        
        if (!success) {
            op_add = !op_add; 
            int attempts = 0;
            while (!success && attempts < 50) {
                if (try_current_op()) success = true;
                attempts++;
            }
            
            if (!success && op_add) {
                for(int k=0; k<500; ++k) {
                   int cu = rnd.next(N), cv = rnd.next(N);
                   if (cu!=cv && deg[cu]<D && deg[cv]<D && !hasEdge(cu,cv)) {
                       u=cu; v=cv; success=true; break;
                   }
               }
            }
        }
        
        
        if (!success) { 
            u = 0; v = 1; 
            
            if (hasEdge(u, v)) {
                op_add = false;
                
                for(size_t k=0; k<existing_edges.size(); ++k) {
                    if ((existing_edges[k].first==u && existing_edges[k].second==v) ||
                        (existing_edges[k].first==v && existing_edges[k].second==u)) {
                        existing_edges[k] = existing_edges.back();
                        existing_edges.pop_back();
                        break;
                    }
                }
            } else {
                op_add = true;
            }
        }

        cout << u << " " << v << "\n";
        
        if (op_add) {
            adj[u].push_back(v);
            adj[v].push_back(u);
            deg[u]++; deg[v]++;
            existing_edges.push_back({u, v});
        } else {
            
            for(size_t k=0; k<adj[u].size(); ++k) if(adj[u][k] == v) { adj[u].erase(adj[u].begin()+k); break; }
            for(size_t k=0; k<adj[v].size(); ++k) if(adj[v][k] == u) { adj[v].erase(adj[v].begin()+k); break; }
            deg[u]--; deg[v]--;
        }
    }

    
    if (mode == "non") {
        for (int i = 0; i < Q; ++i) {
            int x = rnd.next(N);
            int y = rnd.next(N);
            while (y == x) y = rnd.next(N);
            int v_day = (seedVal == 5) ? U : rnd.next(0, U);
            cout << x << " " << y << " " << v_day << "\n";
        }
    }

    return 0;
}