#include <bits/stdc++.h>
using namespace std;
const int MAX = 100128;
const long long INF = 1LL << 50;
struct SegmentTree {
  struct Node {
    long long weight;
    int index;
    Node(long long weight = INF, int index = -1)
        : weight(weight), index(index) {}
    bool operator<(const Node& oth) const {
      return tie(weight, index) < tie(oth.weight, oth.index);
    }
  };
  queue<int> next_id_[MAX];
  Node tree_[4 * MAX];
  long long lazy_[4 * MAX];
  int n_, q_lef_, q_rig_, pos_, val_;
  Node res_;
  void Init(int n) {
    n_ = n;
    memset(lazy_, 0, sizeof(lazy_));
  }
  void AddGirl(int pos, int id) { next_id_[pos].push(id); }
  void Push(int at) {
    lazy_[2 * at] += lazy_[at];
    tree_[2 * at].weight += lazy_[at];
    lazy_[2 * at + 1] += lazy_[at];
    tree_[2 * at + 1].weight += lazy_[at];
    lazy_[at] = 0;
  }
  Node QueryBestGirl(int lef, int rig) {
    q_lef_ = lef;
    q_rig_ = rig;
    res_ = Node();
    QueryRec(1, 0, n_ - 1);
    return res_;
  }
  void QueryRec(int at, int lef, int rig) {
    if (q_lef_ > rig || q_rig_ < lef) return;
    if (q_lef_ <= lef && rig <= q_rig_) {
      res_ = min(res_, tree_[at]);
    } else {
      const int mid = (lef + rig) >> 1;
      Push(at);
      QueryRec(2 * at, lef, mid);
      QueryRec(2 * at + 1, mid + 1, rig);
    }
  }
  void DeleteBest(int pos) {
    pos_ = pos;
    DeleteRec(1, 0, n_ - 1);
  }
  void DeleteRec(int at, int lef, int rig) {
    if (lef == rig) {
      tree_[at] = Node();
      if (!next_id_[lef].empty()) {
        tree_[at] = {next_id_[lef].front() + lazy_[at], next_id_[lef].front()};
        next_id_[lef].pop();
      }
    } else {
      const int mid = (lef + rig) >> 1;
      Push(at);
      if (pos_ <= mid) {
        DeleteRec(2 * at, lef, mid);
      } else {
        DeleteRec(2 * at + 1, mid + 1, rig);
      }
      tree_[at] = min(tree_[2 * at], tree_[2 * at + 1]);
    }
  }
  void Update(int lef, int rig, int val) {
    q_lef_ = lef;
    q_rig_ = rig;
    val_ = val;
    UpdateRec(1, 0, n_ - 1);
  }
  void UpdateRec(int at, int lef, int rig) {
    if (q_lef_ > rig || q_rig_ < lef) return;
    if (q_lef_ <= lef && rig <= q_rig_) {
      tree_[at].weight += val_;
      lazy_[at] += val_;
    } else {
      const int mid = (lef + rig) >> 1;
      Push(at);
      UpdateRec(2 * at, lef, mid);
      UpdateRec(2 * at + 1, mid + 1, rig);
      tree_[at] = min(tree_[2 * at], tree_[2 * at + 1]);
    }
  }
};
template <int MAX_VERTICES>
struct HLDOT {
  static const int LOG = 32 - __builtin_clz(MAX_VERTICES);
  int head_[MAX_VERTICES], pred_[2 * MAX_VERTICES], to_[2 * MAX_VERTICES];
  int par_[LOG][MAX_VERTICES];
  int top_[MAX_VERTICES], size_[MAX_VERTICES], lef_[MAX_VERTICES],
      rig_[MAX_VERTICES];
  int edge_cnt_, next_num_, vertices_;
  vector<pair<int, int>> segs_;
  void Init(int vertices) {
    vertices_ = vertices;
    memset(head_, -1, sizeof(int) * (vertices));
    segs_.reserve(2 * LOG + 1);
  }
  void AddEdge(int a, int b) {
    to_[edge_cnt_] = b;
    pred_[edge_cnt_] = head_[a];
    head_[a] = edge_cnt_++;
    to_[edge_cnt_] = a;
    pred_[edge_cnt_] = head_[b];
    head_[b] = edge_cnt_++;
  }
  void DFS1(int at) {
    size_[at] = 1;
    for (int e = head_[at]; ~e; e = pred_[e]) {
      if (to_[e] != par_[0][at]) {
        par_[0][to_[e]] = at;
        DFS1(to_[e]);
        size_[at] += size_[to_[e]];
      }
    }
  }
  void DFS2(int at, int cur_top) {
    lef_[at] = rig_[at] = next_num_++;
    top_[at] = cur_top;
    int heavy = -1;
    for (int e = head_[at]; ~e; e = pred_[e])
      if (to_[e] != par_[0][at] &&
          (heavy == -1 || size_[to_[e]] > size_[heavy]))
        heavy = to_[e];
    if (heavy == -1) return;
    DFS2(heavy, cur_top);
    for (int e = head_[at]; ~e; e = pred_[e])
      if (to_[e] != par_[0][at] && to_[e] != heavy) DFS2(to_[e], to_[e]);
    rig_[at] = next_num_ - 1;
  }
  bool isAncestor(int a, int b) {
    return lef_[a] <= lef_[b] && rig_[b] <= rig_[a];
  }
  int GetLca(int a, int b) {
    if (isAncestor(a, b)) return a;
    for (int i = LOG - 1; i >= 0; --i)
      if (!isAncestor(par_[i][a], b)) a = par_[i][a];
    return par_[0][a];
  }
  void Process() {
    assert(edge_cnt_ == 2 * (vertices_ - 1));
    next_num_ = 0;
    edge_cnt_ = 0;
    par_[0][0] = 0;
    DFS1(0);
    DFS2(0, 0);
    for (int j = 0; j + 1 < LOG; ++j)
      for (int i = 0; i < vertices_; ++i) par_[j + 1][i] = par_[j][par_[j][i]];
  }
  void QueryUp(int at, int anc) {
    while (top_[at] != top_[anc]) {
      segs_.push_back({lef_[top_[at]], lef_[at]});
      at = par_[0][top_[at]];
    }
    if (at != anc) {
      segs_.push_back({lef_[anc] + 1, lef_[at]});
    }
  }
  const vector<pair<int, int>>& GetSegments(int a, int b) {
    segs_.clear();
    const int lca = GetLca(a, b);
    QueryUp(a, lca);
    QueryUp(b, lca);
    segs_.push_back({lef_[lca], lef_[lca]});
    return segs_;
  }
};
SegmentTree tree;
HLDOT<MAX> hldot;
void solve(const int test_num) {
  (void)test_num;
  int n, m, q;
  scanf("%d %d %d", &n, &m, &q);
  hldot.Init(n);
  for (int e = 0, a, b; e < n - 1; ++e) {
    scanf("%d %d", &a, &b);
    --a;
    --b;
    hldot.AddEdge(a, b);
  }
  hldot.Process();
  tree.Init(n);
  static int live[MAX];
  for (int i = 1; i <= m; ++i) {
    scanf("%d", live + i);
    --live[i];
    tree.AddGirl(hldot.lef_[live[i]], i);
  }
  for (int i = 0; i < n; ++i) tree.DeleteBest(i);
  vector<int> res;
  res.reserve(n);
  SegmentTree::Node best[55];
  while (q-- > 0) {
    int ty;
    scanf("%d", &ty);
    if (ty == 1) {
      int v, u, k;
      scanf("%d %d %d", &v, &u, &k);
      --u, --v;
      res.clear();
      const auto& segs = hldot.GetSegments(v, u);
      const int S = (int)segs.size();
      for (int i = 0; i < S; ++i) {
        best[i] = tree.QueryBestGirl(segs[i].first, segs[i].second);
      }
      while (true) {
        if (k == 0) break;
        int next_seg = 0;
        for (int i = 1; i < S; ++i) {
          if (best[i] < best[next_seg]) {
            next_seg = i;
          }
        }
        if (best[next_seg].index == -1) {
          break;
        }
        --k;
        res.push_back(best[next_seg].index);
        tree.DeleteBest(hldot.lef_[live[res.back()]]);
        best[next_seg] =
            tree.QueryBestGirl(segs[next_seg].first, segs[next_seg].second);
      }
      printf("%d", (int)res.size());
      for (int r : res) printf(" %d", r);
      printf("\n");
    } else {
      int v, k;
      scanf("%d %d", &v, &k);
      --v;
      tree.Update(hldot.lef_[v], hldot.rig_[v], k);
    }
  }
}
void init() {}
int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  srand(1223);
  init();
  int tests = 1;
  for (int test = 1; test <= tests; ++test) {
    solve(test);
  }
  return 0;
}
