#include <bits/stdc++.h>
using namespace std;
const int inf = (1 << 30) - 1;
const long long linf = (1ll << 62) - 1;
const int N = 1e5 + 100;
int n, m;
long double c;
int q;
vector<int> g[N];
vector<pair<int, int>> req[N];
long double cost[N];
bool tp[N];
long double ans[N];
struct segtree {
  segtree(int n) {
    this->n = n;
    sum.assign(n * 4 + 100, 0);
    add.assign(n * 4 + 100, 0);
    sum2.assign(n * 4 + 100, 0);
    len.assign(n * 4 + 100, 0);
    make_rmq(1, 0, n - 1);
  }
  void make_rmq(int i, int l, int r) {
    len[i] = r - l + 1;
    if (l == r) {
      return;
    }
    make_rmq(i * 2, l, (l + r) / 2);
    make_rmq(i * 2 + 1, (l + r) / 2 + 1, r);
  }
  long double get2(int i) {
    return sum2[i] + 2 * add[i] * sum[i] + add[i] * add[i] * len[i];
  }
  long double get(int i) { return sum[i] + len[i] * add[i]; }
  void recalc(int i) {
    sum[i] = get(i * 2) + get(i * 2 + 1);
    sum2[i] = get2(i * 2) + get2(i * 2 + 1);
  }
  void update(int i, int ll, int rr, int l, int r, long double c) {
    if (ll > r || rr < l) {
      return;
    }
    if (l <= ll && rr <= r) {
      return void(add[i] += c);
    }
    update(i * 2, ll, (ll + rr) / 2, l, r, c);
    update(i * 2 + 1, (ll + rr) / 2 + 1, rr, l, r, c);
    recalc(i);
  }
  void update(int l, int r, long double c) { update(1, 0, n - 1, l, r, c); }
  long double total2() { return get2(1); }
  long double total() { return get(1); }
  vector<long double> sum, add, sum2, len;
  int n;
};
int sz[N], hunext[N], parent[N];
void dfsNext(int v, int p = -1) {
  sz[v] = 1;
  parent[v] = p;
  for (int to : g[v]) {
    if (to != p) {
      dfsNext(to, v);
      sz[v] += sz[to];
    }
  }
  hunext[v] = -1;
  for (int to : g[v]) {
    if (to != p && (hunext[v] == -1 || sz[hunext[v]] < sz[to])) {
      hunext[v] = to;
    }
  }
}
vector<vector<int>> hld;
int huindex[N], pos[N];
vector<segtree> rmq;
void build() {
  static bool used[N];
  for (int i = 0; i < n; i++) {
    int cur = i;
    if (!used[cur]) {
      vector<int> path;
      while (cur != -1) {
        used[cur] = true;
        path.push_back(cur);
        cur = hunext[cur];
      }
      hld.push_back(path);
    }
  }
  for (int i = 0; i < ((int)(hld).size()); i++) {
    for (int j = 0; j < ((int)(hld[i]).size()); j++) {
      huindex[hld[i][j]] = i;
      pos[hld[i][j]] = j;
    }
  }
  for (int i = 0; i < ((int)(hld).size()); i++) {
    rmq.emplace_back(((int)(hld[i]).size()));
  }
}
namespace process {
vector<int> vertices;
vector<pair<int, int>> req;
long double cost;
vector<int> rmq[N * 4 + 100];
long double total2 = 0, total = 0;
void add(int x, long double c) {
  while (x != -1) {
    int huindex = ::huindex[x], pos = ::pos[x];
    total2 -= ::rmq[huindex].total2();
    total -= ::rmq[huindex].total();
    ::rmq[huindex].update(0, pos, c);
    total2 += ::rmq[huindex].total2();
    total += ::rmq[huindex].total();
    x = hld[huindex].front();
    x = parent[x];
  }
}
inline long double getAnswer() {
  return c * c - 2 * c * cost * total / n + total2 * cost * cost / n;
}
void update(int i, int ll, int rr, int l, int r, int x) {
  if (ll > r || rr < l) {
    return;
  }
  if (l <= ll && rr <= r) {
    return void(rmq[i].push_back(x));
  }
  update(i * 2, ll, (ll + rr) / 2, l, r, x);
  update(i * 2 + 1, (ll + rr) / 2 + 1, rr, l, r, x);
}
void divideAndConquer(int i, int l, int r) {
  for (int x : rmq[i]) {
    add(x, 1);
  }
  if (l == r) {
    if (req[l].first == 2) {
      ans[req[l].second] = getAnswer();
    }
  } else {
    divideAndConquer(i * 2, l, (l + r) / 2);
    divideAndConquer(i * 2 + 1, (l + r) / 2 + 1, r);
  }
  for (int x : rmq[i]) {
    add(x, -1);
  }
}
void process() {
  vertices.clear();
  for (auto i : req) {
    if (i.first != 2) {
      vertices.push_back(i.second);
    }
  }
  sort((vertices).begin(), (vertices).end()),
      vertices.resize(unique((vertices).begin(), (vertices).end()) -
                      vertices.begin());
  static int last[N];
  for (int i : vertices) {
    last[i] = -1;
  }
  fill_n(rmq, ((int)(req).size()) * 4 + 100, vector<int>());
  for (int i = 0; i < ((int)(req).size()); i++) {
    if (req[i].first == 2) {
      continue;
    }
    if (req[i].first == 0) {
      assert(last[req[i].second] == -1);
      last[req[i].second] = i;
    } else {
      assert(last[req[i].second] != -1);
      update(1, 0, ((int)(req).size()) - 1, last[req[i].second], i,
             req[i].second);
      last[req[i].second] = -1;
    }
  }
  for (int i : vertices) {
    if (last[i] != -1) {
      update(1, 0, ((int)(req).size()) - 1, last[i], ((int)(req).size()) - 1,
             i);
    }
  }
  divideAndConquer(1, 0, ((int)(req).size()) - 1);
}
void process(const vector<pair<int, int>> &req, long double cost) {
  process::req = req;
  process::cost = cost;
  process();
}
}  // namespace process
int main() {
  cin >> n >> m >> q >> c;
  static int cur[N];
  for (int i = 0; i < n; i++) {
    int f;
    scanf("%d", &f), f--;
    req[f].push_back(make_pair(0, i));
    cur[i] = f;
  }
  for (int i = 1; i < n; i++) {
    int p;
    scanf("%d", &p), p--;
    g[p].push_back(i);
  }
  for (int i = 0; i < m; i++) {
    double x;
    scanf("%lf", &x);
    cost[i] = x;
  }
  for (int i = 0; i < q; i++) {
    int t;
    scanf("%d", &t);
    if (t == 1) {
      int x, w;
      scanf("%d%d", &x, &w), x--, w--;
      req[cur[x]].push_back(make_pair(1, x));
      req[w].push_back(make_pair(0, x));
      cur[x] = w;
    } else {
      tp[i] = 1;
      int k;
      scanf("%d", &k), k--;
      req[k].push_back(make_pair(2, i));
    }
  }
  dfsNext(0);
  build();
  for (int i = 0; i < m; i++) {
    if (req[i].empty()) {
      continue;
    }
    process::process(req[i], cost[i]);
  }
  for (int i = 0; i < q; i++) {
    if (tp[i]) {
      printf("%.20lf\n", (double)ans[i]);
    }
  }
  return 0;
}
