#include <bits/stdc++.h>
using namespace std;
int n, k, q, t;
struct tree {
vector<vector<int>> c;
vector<array<int, 20>> jmp;
int root;
vector<int> depth;
vector<vector<pair<int, int>>> extraEdges;
vector<int> dist;
tree(vector<int> p) {
c.resize(n);
jmp.resize(n);
extraEdges.resize(n);
dist.resize(n, INT_MIN);
depth.resize(n);
for (int i = 0; i < p.size(); i++) {
if (p[i] == -1) {
p[i] = i;
root = i;
} else {
p[i]--;
c[p[i]].push_back(i);
}
}
for (int i = 0; i < n; i++) {
jmp[i][0] = p[i];
}
dfs(root);
}
void dfs(int v, int d = 0) {
depth[v] = d;
for (int i = 1; i < 20; i++) {
jmp[v][i] = jmp[jmp[v][i-1]][i-1];
}
for (int u: c[v]) {
dfs(u, d+1);
}
}
int jump(int v, int steps) {
for (int i = 0; i < 20; i++) {
if (steps & (1 << i)) {
v = jmp[v][i];
}
}
return v;
}
int lca(int a, int b) {
if (depth[a] < depth[b]) swap(a, b);
a = jump(a, depth[a] - depth[b]);
if (a == b) return a;
for (int i = 19; i >= 0; i--) {
if (jmp[a][i] != jmp[b][i]) {
a = jmp[a][i];
b = jmp[b][i];
}
}
return jmp[a][0];
}
void addEdge(int a, int b, int w) {
extraEdges[a].push_back({b, w});
extraEdges[b].push_back({a, -w});
}
void dfs_dist(int v, int d) {
if (dist[v] != INT_MIN) return;
dist[v] = d;
for (auto [u, w]: extraEdges[v]) {
dfs_dist(u, d + w);
}
}
void process() {
dfs_dist(0, 0);
}
int solve(int a, int b) {
int p = lca(a, b);
if (dist[a] == INT_MIN || dist[b] == INT_MIN || dist[p] == INT_MIN) {
cerr << "Error: distance not found\n";
return -1;
}
return dist[a] + dist[b] - 2*dist[p];
}
};
tree read_tree() {
vector<int> p(n);
for (int i = 0; i < n; i++) cin >> p[i];
return tree(p);
}
int main() {
cin >> n >> k >> q >> t;
tree t1 = read_tree();
tree t2 = read_tree();
for (int i = 0; i < k; i++) {
if (i) cout << " ";
cout << i+1;
}
cout << "\n";
for (int i = 0; i < k-1; i++) {
cout << "? " << i+1 << " " << i+2 << "\n";
}
cout << "!\n";
cout.flush();
for (int i = 0; i < k-1; i++) {
int a, b, c, d;
cin >> a >> b >> c >> d;
int lca1 = t1.lca(i, i+1);
int lca2 = t2.lca(i, i+1);
t1.addEdge(lca1, i, a);
t1.addEdge(lca1, i+1, b);
t2.addEdge(lca2, i, c);
t2.addEdge(lca2, i+1, d);
// cout << "Tree 1: Adding edge " << lca1+1 << " - " << i+1 << " with weight " << a << "\n";
// cout << "Tree 1: Adding edge " << lca1+1 << " - " << i+2 << " with weight " << b << "\n";
// cout << "Tree 2: Adding edge " << lca2+1 << " - " << i+1 << " with weight " << c << "\n";
// cout << "Tree 2: Adding edge " << lca2+1 << " - " << i+2 << " with weight " << d << "\n";
}
t1.process();
t2.process();
/*for (int i = 0; i < n; i++) {
if (t1.dist[i] != INT_MIN) {
cout << "Tree 1: Depth of node " << i+1 << " is " << t1.dist[i] << "\n";
}
}
for (int i = 0; i < n; i++) {
if (t2.dist[i] != INT_MIN) {
cout << "Tree 2: Depth of node " << i+1 << " is " << t2.dist[i] << "\n";
}
}*/
vector<pair<int, int>> queries;
for (int i = 0; i < t; i++) {
int a, b;
cin >> a >> b;
a--; b--;
queries.push_back({a, b});
}
for (auto [a, b]: queries) {
cout << t1.solve(a, b) << " " << t2.solve(a, b) << "\n";
}
}
/*
9 3 2 3
2 -1 2 1 1 5 1 4 5
9 4 5 5 7 3 -1 3 7
3 0 5 13
0 1 10 7
1 2
2 3
3 1
*/