#include <bits/stdc++.h>
using namespace std;
template <typename State>
struct PriorityQueue {
  template <typename... Args>
  void emplace(Args &&...args) {
    m_heap.emplace_back(forward<Args>(args)...);
    push_heap(m_heap.begin(), m_heap.end(), m_comp);
  }
  bool empty() const { return m_heap.empty(); }
  State const &top() const { return m_heap.front(); }
  void pop() {
    pop_heap(m_heap.begin(), m_heap.end(), m_comp);
    m_heap.pop_back();
  }
  void clear() { m_heap.clear(); }
  vector<State> m_heap;
  greater<State> m_comp;
};
struct Edge {
  Edge() = default;
  Edge(int64_t weight, int from, int to)
      : m_weight(weight), m_from(from), m_to(to) {}
  int64_t m_weight = 0;
  int m_from = 0;
  int m_to = 0;
};
struct Graph {
  explicit Graph(int n) : m_adj(n) {}
  int NumVertices() const { return m_adj.size(); }
  void AddEdge(Edge const &edge) {
    assert(edge.m_from < m_adj.size());
    assert(edge.m_to < m_adj.size());
    m_adj[edge.m_from].push_back(m_edges.size());
    m_edges.push_back(edge);
  }
  void IncWeight(int edge) {
    assert(edge < m_edges.size());
    ++m_edges[edge].m_weight;
  }
  template <typename Fn>
  void ForEachOutgoingEdge(int u, Fn &&fn) const {
    for (int i : m_adj[u]) fn(m_edges[i]);
  }
  vector<vector<int>> m_adj;
  vector<Edge> m_edges;
};
struct State {
  State() = default;
  State(int64_t distance, int u) : m_distance(distance), m_u(u) {}
  bool operator>(State const &rhs) const { return m_distance > rhs.m_distance; }
  int64_t m_distance = 0;
  int m_u = 0;
};
vector<State> zero;
vector<State> one;
vector<State> two;
PriorityQueue<State> many;
void Dijkstra(Graph const &graph, vector<int64_t> const &oldDistance,
              vector<int64_t> &newDistance) {
  newDistance.assign(graph.NumVertices(), -1);
  newDistance[0] = 0;
  zero.emplace_back(newDistance[0], 0);
  while (!zero.empty() || !one.empty() || !two.empty() || !many.empty()) {
    State state;
    if (zero.empty() && one.empty() && two.empty()) {
      state = many.top();
      many.pop();
    } else {
      if (zero.empty()) {
        if (!one.empty()) {
          zero.swap(one);
          one.swap(two);
        } else {
          zero.swap(two);
        }
      }
      assert(!zero.empty());
      state = zero.back();
      zero.pop_back();
    }
    if (state.m_distance != newDistance[state.m_u]) continue;
    graph.ForEachOutgoingEdge(state.m_u, [&](Edge const &edge) {
      auto const weight =
          edge.m_weight + oldDistance[edge.m_from] - oldDistance[edge.m_to];
      auto const ndistance = state.m_distance + weight;
      if (newDistance[edge.m_to] < 0 || newDistance[edge.m_to] > ndistance) {
        newDistance[edge.m_to] = ndistance;
        if (weight == 0)
          zero.emplace_back(ndistance, edge.m_to);
        else if (weight == 1)
          one.emplace_back(ndistance, edge.m_to);
        else if (weight == 2)
          two.emplace_back(ndistance, edge.m_to);
        else
          many.emplace(ndistance, edge.m_to);
      }
    });
  }
  for (int i = 0; i < graph.NumVertices(); ++i) {
    if (oldDistance[i] >= 0) newDistance[i] += oldDistance[i];
  }
}
int main() {
  int n, m, q;
  scanf("%d%d%d", &n, &m, &q);
  Graph graph(n);
  for (int i = 0; i < m; ++i) {
    int weight;
    int from;
    int to;
    scanf("%d%d%d", &from, &to, &weight);
    --from, --to;
    graph.AddEdge(Edge(weight, from, to));
  }
  vector<int64_t> oldDistance(n, 0);
  vector<int64_t> newDistance(n, -1);
  bool dirty = true;
  for (int i = 0; i < q; ++i) {
    int type;
    scanf("%d", &type);
    if (type == 1) {
      int v;
      scanf("%d", &v);
      if (dirty) {
        Dijkstra(graph, oldDistance, newDistance);
        oldDistance.swap(newDistance);
        dirty = false;
      }
      auto const d = static_cast<long long>(oldDistance[v - 1]);
      printf("%I64d\n", d);
    } else {
      assert(type == 2);
      int c, k;
      scanf("%d", &c);
      for (int j = 0; j < c; ++j) {
        scanf("%d", &k);
        graph.IncWeight(k - 1);
      }
      dirty = true;
    }
  }
  return 0;
}
