Problem: Vasya plays a popular game the Gnomes of Might and Magic.

In this game Vasya manages the kingdom of gnomes, consisting of several castles, connected by bidirectional roads. The kingdom road network has a special form. The kingdom has m main castles a1, a2, ..., am, which form the Good Path. This path consists of roads between the castles ai, ai + 1 (1 ≤ i < m) as well as the road between am and a1. There are no other roads between the castles of the Good Path.

In addition, for each pair of neighboring Good Path castles u and v there is exactly one Evil Shortcut — a path that goes along the roads leading from the first castle (u) to the second one (v) and not having any common vertexes with the Good Path except for the vertexes u and v. It is known that there are no other roads and castles in the kingdom there, that is, every road and every castle lies either on the Good Path or the Evil Shortcut (castles can lie in both of them). In addition, no two Evil Shortcuts have any common castles, different than the castles of the Good Path.

At the beginning of each week in the kingdom appears one very bad gnome who stands on one of the roads of the kingdom, and begins to rob the corovans going through this road. One road may accumulate multiple very bad gnomes. Vasya cares about his corovans, so sometimes he sends the Mission of Death from one castle to another.

Let's suggest that the Mission of Death should get from castle s to castle t. Then it will move from castle s to castle t, destroying all very bad gnomes, which are on the roads of the Mission's path. Vasya is so tough that his Mission of Death can destroy any number of gnomes on its way. However, Vasya is very kind, so he always chooses such path between castles s and t, following which he will destroy the smallest number of gnomes. If there are multiple such paths, then Vasya chooses the path that contains the smallest number of roads among them. If there are multiple such paths still, Vasya chooses the lexicographically minimal one among them.

Help Vasya to simulate the life of the kingdom in the Gnomes of Might and Magic game.

A path is a sequence of castles, such that each pair of the neighboring castles on the path is connected by a road. Also, path x1, x2, ... , xp is lexicographically less than path y1, y2, ... , yq, if either p < q and x1 = y1, x2 = y2, ... , xp = yp, or exists such number r (r < p, r < q), that x1 = y1, x2 = y2, ... , xr = yr and xr + 1 < yr + 1.

Input

The first line contains two integers n and m (3 ≤ m ≤ n ≤ 100000) — the number of castles in the kingdom, and the number of castles on the Good Path, respectively.

The second line contains m integers, which are numbers of Good Path castles (the castles are numbered from 1 to n) in the order of occurrence on the Path, starting with some castle. All Good Path castles are different.

Each of the following m lines describes an Evil Shortcut. First a line contains an integer ki (3 ≤ ki ≤ 100000) — the number of castles on the corresponding Evil Shortcut (with the two castles which are on the Good Path), followed by a ki integers — number of castles in the order of occurrence in the given Shortcut. All castles in one Evil Shortcut are different. It is guaranteed that the first and the last castles from the Shortcut are on the Good Path and the first castles in the Evil Shortcuts form the Good Path and are presented in the same order in which the Path was represented on the second line.

The next line contains an integer q (1 ≤ q ≤ 100000) — the number of events in the life of the kingdom. Each of the following q lines describes a single event. An event is described by the symbol cj and two numbers or castles sj and tj (the character and numbers of castles are separated by a single space). If the character of cj is equal to "+" (a plus), it means that a very bad gnome (probably not the first one) has appeared on the road between castles sj and tj. If cj equals "?" (a question), then Vasya sent a Mission of Death from castle sj to castle tj. It is guaranteed that for each request "+", the road between castles sj and tj exists. The events are given in chronological order, starting with the earliest one. Initially there are no very bad gnomes on the roads.

All numbers in all lines are separated by single spaces. It is guaranteed that all the given Evil Shortcuts and Good Path fit in the limitations given in the problem statement.

Output

For each query "?" print a single number on a single line — the number of very bad gnomes destroyed by the corresponding Mission of Death. Print the answers to queries in the chronological order.

Examples

Input

6 3
1 2 3
3 1 4 2
3 2 5 3
3 3 6 1
10
+ 1 2
+ 4 2
+ 1 3
+ 2 3
? 1 2
+ 2 5
? 1 2
? 1 2
+ 1 2
? 1 2


Output

0
1
0
1

Note

In the example after the first four requests there is only one path from castle 1 to castle 2, which does not contain roads with very bad gnomes: 1 <image> 6 <image> 3 <image> 5 <image> 2.

After a gnome stood on the road (2, 5), the next Mission of Death moves along path 1 <image> 2, and destroys the gnome, who was on the road (1, 2). The next Mission of Death follows the same path which is already free of gnomes.

After yet another gnome stood on the road (1, 2), the next Mission of Death goes on the path 1 <image> 2, and kills the gnome.

Solution (in CPP):

Solution:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 111111;
int treeSize[maxn];
int IDSection[maxn];
int IDKey[maxn];
int root[maxn];
int goodCastle[maxn];
int goodPath[maxn];
vector<int> evilCastle[maxn];
int n, m;
struct SubSegTree {
  int sz;
  int lch[maxn << 2];
  int rch[maxn << 2];
  int evilPath[maxn << 2];
  bool clear[maxn << 2];
  void build(int l, int r, int &rt) {
    rt = sz++;
    evilPath[rt] = 0;
    if (l == r) {
      return;
    }
    int mid = (l + r) >> 1;
    build(l, mid, lch[rt]);
    build(mid + 1, r, rch[rt]);
  }
  void PushDown(int rt) {
    if (clear[rt]) {
      clear[lch[rt]] = true;
      clear[rch[rt]] = true;
      evilPath[lch[rt]] = 0;
      evilPath[rch[rt]] = 0;
      clear[rt] = false;
    }
  }
  void PushUp(int rt) { evilPath[rt] = evilPath[lch[rt]] + evilPath[rch[rt]]; }
  void add(int pos, int l, int r, int rt) {
    if (l == r) {
      evilPath[rt]++;
      return;
    }
    PushDown(rt);
    int mid = (l + r) >> 1;
    if (pos <= mid)
      add(pos, l, mid, lch[rt]);
    else
      add(pos, mid + 1, r, rch[rt]);
    PushUp(rt);
  }
  void death(int L, int R, int l, int r, int rt) {
    if (L <= l && r <= R) {
      clear[rt] = true;
      evilPath[rt] = 0;
      return;
    }
    PushDown(rt);
    int mid = (l + r) >> 1;
    if (L <= mid) death(L, R, l, mid, lch[rt]);
    if (mid < R) death(L, R, mid + 1, r, rch[rt]);
    PushUp(rt);
  }
  int query(int L, int R, int l, int r, int rt) {
    if (L <= l && r <= R) {
      return evilPath[rt];
    }
    PushDown(rt);
    int mid = (l + r) >> 1;
    int ret = 0;
    if (L <= mid) ret += query(L, R, l, mid, lch[rt]);
    if (mid < R) ret += query(L, R, mid + 1, r, rch[rt]);
    return ret;
  }
} subTree;
struct Node {
  int sum, num, leftID, rightID;
  void reset(int a = 0, int b = 0, int c = 0, int d = 0) {
    sum = a;
    num = b;
    leftID = c;
    rightID = d;
  }
  bool operator<(const Node &cmp) {
    if (sum == cmp.sum) {
      return num < cmp.num;
    }
    return sum < cmp.sum;
  }
  void operator+=(const Node &add) {
    this->sum += add.sum;
    this->num += add.num;
  }
};
struct SegTree {
  Node road[maxn << 2];
  bool clear[maxn << 2];
  int isLeaf[maxn << 2];
  void kill(int rt) {
    road[rt].sum = 0;
    if (isLeaf[rt] != -1) {
      int l = isLeaf[rt];
      if (road[rt].num == 1) {
        goodPath[l] = 0;
      } else {
        subTree.death(1, treeSize[l], 1, treeSize[l], root[l]);
      }
    }
  }
  void PushDown(int rt) {
    if (clear[rt]) {
      clear[rt << 1] = true;
      clear[rt << 1 | 1] = true;
      kill(rt << 1);
      kill(rt << 1 | 1);
      clear[rt] = 0;
    }
  }
  void PushUp(int rt) {
    road[rt].reset();
    road[rt] += road[rt << 1];
    road[rt] += road[rt << 1 | 1];
    road[rt].leftID = road[rt << 1].leftID;
    road[rt].rightID = road[rt << 1 | 1].rightID;
  }
  void build(int l, int r, int rt) {
    road[rt].reset(0, r - l + 1, goodCastle[l % m + 1], goodCastle[r]);
    clear[rt] = false;
    isLeaf[rt] = -1;
    if (l == r) {
      isLeaf[rt] = l;
      subTree.build(1, treeSize[l], root[l]);
      return;
    }
    int mid = (l + r) >> 1;
    build(l, mid, rt << 1);
    build(mid + 1, r, rt << 1 | 1);
    PushUp(rt);
  }
  void updateLeaf(int rt, int l) {
    int a = goodPath[l];
    int b = subTree.query(1, treeSize[l], 1, treeSize[l], root[l]);
    if (a <= b) {
      road[rt].reset(a, 1, goodCastle[l % m + 1], goodCastle[l]);
    } else {
      road[rt].reset(b, treeSize[l], evilCastle[l][2],
                     evilCastle[l][treeSize[l]]);
    }
  }
  void add(int pos, int pos2, int l, int r, int rt) {
    if (l == r) {
      if (pos2 == -1) {
        goodPath[l]++;
      } else {
        subTree.add(pos2, 1, treeSize[l], root[l]);
      }
      updateLeaf(rt, l);
      return;
    }
    PushDown(rt);
    int mid = (l + r) >> 1;
    if (pos <= mid)
      add(pos, pos2, l, mid, rt << 1);
    else
      add(pos, pos2, mid + 1, r, rt << 1 | 1);
    PushUp(rt);
  }
  void death(int L, int R, int l, int r, int rt, int LL = -1, int RR = -1) {
    if (L <= l && r <= R) {
      if (LL == -1) {
        clear[rt] = true;
        kill(rt);
      } else {
        subTree.death(LL, RR, 1, treeSize[l], root[l]);
        updateLeaf(rt, l);
      }
      return;
    }
    PushDown(rt);
    int mid = (l + r) >> 1;
    if (L <= mid) death(L, R, l, mid, rt << 1, LL, RR);
    if (mid < R) death(L, R, mid + 1, r, rt << 1 | 1, LL, RR);
    PushUp(rt);
  }
  Node query(int L, int R, int l, int r, int rt) {
    if (L <= l && r <= R) {
      return road[rt];
    }
    PushDown(rt);
    int mid = (l + r) >> 1;
    if (R <= mid)
      return query(L, R, l, mid, rt << 1);
    else if (mid < L)
      return query(L, R, mid + 1, r, rt << 1 | 1);
    else {
      Node ll = query(L, R, l, mid, rt << 1);
      Node rr = query(L, R, mid + 1, r, rt << 1 | 1);
      Node ret;
      ret.reset(ll.sum + rr.sum, ll.num + rr.num, ll.leftID, rr.rightID);
      return ret;
    }
  }
} tree;
struct ShortPath {
  struct EdgeNode {
    int dis, v, next, num;
  };
  vector<EdgeNode> edge[9];
  int bestSum, bestNum;
  int bestPath[9];
  int bestNode[9];
  int bestDeep;
  int path[9];
  int node[9];
  int s, t;
  bool vis[9];
  void calcPos(int S, int &SectionS, int &KeyS) {
    if (S == 0) {
      SectionS = IDSection[s];
      KeyS = IDKey[s];
    } else if (S == 1) {
      SectionS = IDSection[s];
      KeyS = 1;
    } else if (S == 2) {
      SectionS = IDSection[s] % m + 1;
      KeyS = 1;
    } else if (S == 3) {
      SectionS = IDSection[t];
      KeyS = 1;
    } else if (S == 4) {
      SectionS = IDSection[t] % m + 1;
      KeyS = 1;
    } else {
      SectionS = IDSection[t];
      KeyS = IDKey[t];
    }
  }
  int chooseNext(int s, int dir) {
    if (dir == -1) s -= 1;
    if (s == 0) s = m;
    int good = goodPath[s];
    int evil = subTree.query(1, treeSize[s], 1, treeSize[s], root[s]);
    if (dir == -1) {
      if (evil < good ||
          (evil == good && evilCastle[s][treeSize[s]] < goodCastle[s])) {
        return evilCastle[s][treeSize[s]];
      } else {
        return goodCastle[s];
      }
    } else {
      if (evil < good ||
          (evil == good && evilCastle[s][1] < goodCastle[s % m + 1])) {
        return evilCastle[s][1];
      } else {
        return goodCastle[s % m + 1];
      }
    }
  }
  void makeEdge(int S, int T) {
    EdgeNode e;
    e.v = T;
    int SectionS, SectionT, KeyS, KeyT;
    calcPos(S, SectionS, KeyS);
    calcPos(T, SectionT, KeyT);
    if (SectionS == SectionT && KeyS == KeyT) {
      e.next = -1;
      e.num = 0;
      e.dis = 0;
    } else if (S == 0 || T == 5) {
      if (SectionS == SectionT) {
        if (KeyS > KeyT) {
          e.dis = subTree.query(KeyT, KeyS - 1, 1, treeSize[SectionT],
                                root[SectionT]);
          e.num = KeyS - KeyT;
          e.next = evilCastle[SectionS][KeyS - 1];
        } else {
          e.dis = subTree.query(KeyS, KeyT - 1, 1, treeSize[SectionS],
                                root[SectionS]);
          e.num = KeyT - KeyS;
          e.next = evilCastle[SectionS][KeyS + 1];
        }
      } else {
        if (SectionS % m + 1 == SectionT) {
          e.dis = subTree.query(KeyS, treeSize[SectionS], 1, treeSize[SectionS],
                                root[SectionS]);
          e.num = treeSize[SectionS] - KeyS + 1;
          e.next = evilCastle[SectionS][KeyS + 1];
        } else {
          e.dis = subTree.query(KeyT, treeSize[SectionT], 1, treeSize[SectionT],
                                root[SectionT]);
          e.num = treeSize[SectionT] - KeyT + 1;
          e.next = evilCastle[SectionT][treeSize[SectionT]];
        }
      }
    } else {
      if (S + T == 3 || S + T == 7) {
        if (SectionS % m + 1 == SectionT) {
          Node a = tree.query(SectionS, SectionS, 1, m, 1);
          e.dis = a.sum;
          e.num = a.num;
          e.next = a.leftID;
        } else {
          Node a = tree.query(SectionT, SectionT, 1, m, 1);
          e.dis = a.sum;
          e.num = a.num;
          e.next = a.rightID;
        }
      } else if (S == 2) {
        if (SectionS < SectionT) {
          Node a = tree.query(SectionS, SectionT - 1, 1, m, 1);
          e.dis = a.sum;
          e.num = a.num;
          e.next = a.leftID;
        } else {
          Node b = tree.query(SectionS, m, 1, m, 1);
          if (SectionT != 1) {
            Node c = tree.query(1, SectionT - 1, 1, m, 1);
            b += c;
            b.rightID = c.rightID;
          }
          e.dis = b.sum;
          e.num = b.num;
          e.next = b.leftID;
        }
      } else {
        if (SectionS > SectionT) {
          Node a = tree.query(SectionT, SectionS - 1, 1, m, 1);
          e.dis = a.sum;
          e.num = a.num;
          e.next = a.rightID;
        } else {
          Node b = tree.query(SectionT, m, 1, m, 1);
          if (SectionS != 1) {
            Node c = tree.query(1, SectionS - 1, 1, m, 1);
            b += c;
            b.rightID = c.rightID;
          }
          e.dis = b.sum;
          e.num = b.num;
          e.next = b.rightID;
        }
      }
    }
    edge[S].push_back(e);
  }
  void copy(int sum, int num, int deep) {
    bestSum = sum;
    bestNum = num;
    bestDeep = deep;
    for (int i = 0; i < deep; i++) {
      bestNode[i] = node[i];
      bestPath[i] = path[i];
    }
  }
  void dfs(int deep, int u, int sum, int num) {
    if (u == 5) {
      if (sum < bestSum || bestSum == -1) {
        copy(sum, num, deep);
      } else if (sum == bestSum && num < bestNum) {
        copy(sum, num, deep);
      } else if (sum == bestSum && num == bestNum) {
        bool cp = true;
        int i = 0, j = 0;
        while (i < deep && j < bestDeep) {
          while (node[i] == -1) i++;
          while (bestNode[j] == -1) j++;
          if (node[i] != bestNode[j]) {
            cp = node[i] < bestNode[j];
            break;
          }
          i++, j++;
        }
        if (cp) copy(sum, num, deep);
      }
      return;
    }
    for (int i = 0; i < edge[u].size(); i++) {
      int v = edge[u][i].v;
      if (vis[v]) continue;
      vis[v] = true;
      path[deep] = u;
      node[deep] = edge[u][i].next;
      dfs(deep + 1, v, sum + edge[u][i].dis, num + edge[u][i].num);
      vis[v] = false;
    }
  }
  void missionOfDeath(int S, int T) {
    int SectionS, SectionT, KeyS, KeyT;
    calcPos(S, SectionS, KeyS);
    calcPos(T, SectionT, KeyT);
    if (SectionS == SectionT && KeyS == KeyT) {
      return;
    } else if (S == 0 || T == 5) {
      if (SectionS == SectionT) {
        if (KeyS > KeyT) {
          tree.death(SectionT, SectionT, 1, m, 1, KeyT, KeyS - 1);
        } else {
          tree.death(SectionS, SectionS, 1, m, 1, KeyS, KeyT - 1);
        }
      } else {
        if (SectionS % m + 1 == SectionT) {
          tree.death(SectionS, SectionS, 1, m, 1, KeyS, treeSize[SectionS]);
        } else {
          tree.death(SectionT, SectionT, 1, m, 1, KeyT, treeSize[SectionT]);
        }
      }
    } else {
      if (S + T == 3 || S + T == 7) {
        if (SectionS % m + 1 == SectionT) {
          tree.death(SectionS, SectionS, 1, m, 1);
        } else {
          tree.death(SectionT, SectionT, 1, m, 1);
        }
      } else if (S == 2) {
        if (SectionS < SectionT) {
          tree.death(SectionS, SectionT - 1, 1, m, 1);
        } else {
          tree.death(SectionS, m, 1, m, 1);
          if (SectionT != 1) tree.death(1, SectionT - 1, 1, m, 1);
        }
      } else {
        if (SectionS > SectionT) {
          tree.death(SectionT, SectionS - 1, 1, m, 1);
        } else {
          tree.death(SectionT, m, 1, m, 1);
          if (SectionS != 1) tree.death(1, SectionS - 1, 1, m, 1);
        }
      }
    }
  }
  void debugEdge() {
    for (int i = 0; i < 6; i++) {
      printf("%d:", i);
      for (int j = 0; j < edge[i].size(); j++) {
        printf("{%d %d %d %d}", edge[i][j].v, edge[i][j].next, edge[i][j].dis,
               edge[i][j].num);
      }
      puts("");
    }
  }
  void calcShortPath(int _s, int _t) {
    s = _s, t = _t;
    if (s == t) {
      puts("0");
    } else {
      for (int i = 0; i < 6; i++) {
        edge[i].clear();
      }
      makeEdge(0, 1);
      makeEdge(0, 2);
      makeEdge(1, 2);
      makeEdge(1, 4);
      makeEdge(2, 1);
      makeEdge(2, 3);
      makeEdge(3, 4);
      makeEdge(4, 3);
      makeEdge(3, 5);
      makeEdge(4, 5);
      if (IDSection[s] == IDSection[t]) {
        makeEdge(0, 5);
        EdgeNode e;
        e.dis = e.num = 0;
        e.next = -1;
        e.v = 3;
        edge[1].push_back(e);
        e.v = 4;
        edge[2].push_back(e);
      }
      bestSum = -1;
      memset(vis, false, sizeof(vis));
      dfs(0, 0, 0, 0);
      printf("%d\n", bestSum);
      bestPath[bestDeep] = 5;
      for (int i = 0; i < bestDeep; i++) {
        missionOfDeath(bestPath[i], bestPath[i + 1]);
      }
    }
  }
} G;
void Initialize() {
  scanf("%d%d", &n, &m);
  for (int i = 1; i <= m; i++) {
    scanf("%d", &goodCastle[i]);
  }
  for (int i = 1; i <= m; i++) {
    scanf("%d", &treeSize[i]);
    evilCastle[i].push_back(-1);
    for (int j = 1; j <= treeSize[i]; j++) {
      int node;
      scanf("%d", &node);
      evilCastle[i].push_back(node);
      if (j == treeSize[i]) continue;
      IDSection[node] = i;
      IDKey[node] = j;
    }
    treeSize[i]--;
  }
  tree.build(1, m, 1);
}
void addGnome(int s, int t) {
  if (IDKey[s] == 1 && IDKey[t] == 1) {
    int pos;
    if (IDSection[s] % m + 1 == IDSection[t]) {
      pos = IDSection[s];
    } else {
      pos = IDSection[t];
    }
    tree.add(pos, -1, 1, m, 1);
  } else {
    int pos, pos2;
    if (IDSection[s] == IDSection[t]) {
      pos = IDSection[s];
      pos2 = min(IDKey[s], IDKey[t]);
    } else {
      if (IDKey[t] == 1) {
        pos = IDSection[s];
        pos2 = IDKey[s];
      } else {
        pos = IDSection[t];
        pos2 = IDKey[t];
      }
    }
    tree.add(pos, pos2, 1, m, 1);
  }
}
void Query() {
  int Q;
  scanf("%d", &Q);
  while (Q--) {
    char op;
    int s, t;
    scanf("%*c%c %d %d", &op, &s, &t);
    if (op == '+')
      addGnome(s, t);
    else
      G.calcShortPath(s, t);
  }
}
int main() {
  Initialize();
  Query();
  return 0;
}