# BZOJ3091 城市旅行

1、若x和y直接相连，断开x和y之间直接相连的边；

2、若x和y不连通，连接x和y；

3、若x和y连通，将x到y的路径上的每个点的点权+d；

4、若x和y连通，求：在x到y的路径上随机选两个点s和t，求s到t路径上的点权和的期望值。注意s和t与t和s算一种方案。

x的期望即左右儿子的期望和加上路径端点分别在左儿子内部和右儿子内部（或者在x上）的期望。

x->e

= x->l->e //端点都在左儿子内

+ x->r->e //端点都在右儿子内

+ (x->l->s + 1) * x->r->rm//一端点在x上或者左儿子内、另一端点在右儿子内时，右儿子整体产生的贡献

+ (x->r->s + 1) * x->l->lm//……………………时，左儿子整体产生的贡献

+ (x->l->s + 1) * (x->r->s + 1) * x->v//x自身的贡献

//BZOJ3091; travel; LCT
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <climits>
#include <cmath>
#include <utility>
#include <set>
#include <map>
#include <queue>
#include <ios>
#include <iomanip>
#include <ctime>
#include <numeric>
#include <functional>
#include <fstream>
#include <string>
#include <vector>
#include <bitset>
#include <cstdarg>
using namespace std;

typedef long long ll;
typedef unsigned int uint;
#define pair(x, y) make_pair(x, y)

#define SIZE 2000000

char buffer[SIZE], *ip = buffer;

static uint r;
r = 0U;
while (*ip < '0' || *ip > '9') ++ip;
while (*ip >= '0' && *ip <= '9') r = r * 10U + (uint)(*(ip++) - '0');
return (ll)r;
}

#define N 50000

ll sqr[N + 1];

class Node {
public:
Node *l, *r, *f;
bool rev;
ll lm, rm;
//Sigma{ i * a[i] }, Sigma{ (s-i+1) * a[i] }
ll sum, e, v, d;
//Sum, Expected value, Value, Delta
int s;
//Size
Node(ll _v) {
l = r = f = NULL;
rev = false;
s = 1, d = 0LL, e = sum = lm = rm = v = _v;
}
} *p[N + 1];

ll sum(ll l, ll r) {
return (l + r) * (r - l + 1LL) >> 1;
}

inline void applyDelta(Node *x, ll d) {
ll ds = sum(1LL, x->s), ex;
x->sum += (ll)x->s * d;
x->lm += ds * d, x->rm += ds * d;
x->d += d, x->v += d;
//Expected value
ex = ds * (ll)(x->s + 1) - sqr[x->s];
x->e += ex * d;
}

inline void push(Node *x) {
if (x->rev) {
if (x->l) x->l->rev ^= 1, swap(x->l->lm, x->l->rm);
if (x->r) x->r->rev ^= 1, swap(x->r->lm, x->r->rm);
swap(x->l, x->r);
x->rev = false;
}
if (x->d) {
if (x->l) applyDelta(x->l, x->d);
if (x->r) applyDelta(x->r, x->d);
x->d = 0;
}
}

inline void update(Node *x) {
x->sum = x->v + (x->l ? x->l->sum : 0) + (x->r ? x->r->sum : 0);
x->s = 1 + (x->l ? x->l->s : 0) + (x->r ? x->r->s : 0);
x->e = x->v + (x->l ? x->l->e : 0LL) + (x->r ? x->r->e : 0LL);
x->lm = x->rm = x->v;
if (x->l && !(x->r)) {
x->e += x->l->lm;
x->e += (ll)x->l->s * x->v;
x->lm += x->l->lm + x->v * (ll)x->l->s;
x->rm += x->l->rm + x->l->sum;
} else if (x->r && !(x->l)) {
x->e += x->r->rm;
x->e += (ll)x->r->s * x->v;
x->rm += x->r->rm + x->v * (ll)x->r->s;
x->lm += x->r->lm + x->r->sum;
} else if (x->l && x->r) {
//Expected value
x->e += (ll)(x->l->s + 1) * x->r->rm;
x->e += (ll)(x->r->s + 1) * x->l->lm;
x->e += (ll)(x->l->s + 1) * (x->r->s + 1) * x->v - x->v;
//Left multiplication
x->lm += x->l->lm + x->r->lm + (x->v + x->r->sum) * (ll)x->l->s + x->r->sum;
//Right multiplication
x->rm += x->l->rm + x->r->rm + (x->v + x->l->sum) * (ll)x->r->s + x->l->sum;
}
}

inline void zig(Node *x) {
Node *y = x->f;
Node *z = y->f;
push(x);
if (z && z->l == y) z->l = x;
else if (z && z->r == y) z->r = x;
if (x->r) x->r->f = y;
y->l = x->r;
x->r = y, y->f = x, x->f = z;
update(y);
}

inline void zag(Node *x) {
Node *y = x->f;
Node *z = y->f;
push(x);
if (z && z->l == y) z->l = x;
else if (z && z->r == y) z->r = x;
if (x->l) x->l->f = y;
y->r = x->l;
x->l = y, y->f = x, x->f = z;
update(y);
}

inline bool isRoot(Node *x) {
return !(x->f) || (x->f->l != x && x->f->r != x);
}

inline void splay(Node *x) {
Node *y, *z;
while (!isRoot(x)) {
y = x->f;
z = y->f;
if (z) push(z);
push(y);
if (isRoot(y)) {
if (y->l == x) zig(x);
else zag(x);
} else {
if (z->l == y) {
if (y->l == x) zig(y), zig(x);
else zag(x), zig(x);
} else {
if (y->l == x) zig(x), zag(x);
else zag(y), zag(x);
}
}
}
push(x);
update(x);
}

inline void expose(Node *x) {
for (Node *y = NULL; x != NULL; x = x->f) {
splay(x);
x->r = y;
update(y = x);
}
}

inline void makeRoot(Node *x) {
expose(x);
splay(x);
x->rev ^= 1;
swap(x->lm, x->rm);
}

inline bool cut(int _x, int _y) {
Node *x = p[_x], *y = p[_y];
expose(y);
splay(y);
push(y);
if (y->l) for (push(y = y->l); y->r; push(y = y->r)) ;
if (x == y) {
y = p[_y];
expose(x);
splay(y);
y->f = NULL;
return true;
}
return false;
/*
expose(x);
splay(y);
if (y->f == x) y->f = NULL;
else {
expose(y);
splay(x);
if (x->f == y) x->f = NULL;
}
*/
}

inline void link(Node *x, Node *y) {
makeRoot(x);
x->f = y;
}

inline bool connected(int _x, int _y) {
Node *x = p[_x], *y = p[_y];
expose(y);
for (Node *y = NULL; x != NULL; x = x->f) {
splay(x);
if (!(x->f)) break;
y = x;
}
push(x);
while (x->r) push(x = x->r);
return x == p[_y];
}

struct edge {
int next, node;
} e[N << 1 | 1];
int head[N + 1], tot = 0;

inline void addedge(int a, int b) {
head[a] = tot, e[tot].node = b;
}

int n, m, a[N + 1], x, y, d;
bool v[N + 1];

void build(int x) {
v[x] = true;
for (int i = head[x]; i; i = e[i].next) {
int node = e[i].node;
if (v[node]) continue;
p[node]->f = p[x];
build(node);
}
}

inline void modify(int _x, int _y, ll d) {
Node *x = p[_x], *y = p[_y];
expose(y);
for (y = NULL; x != NULL; x = x->f) {
splay(x);
if (!(x->f)) {
if (x->r) applyDelta(x->r, d);
if (y) applyDelta(y, d);
x->v += d;
}
x->r = y;
update(y = x);
}
}

inline pair <ll, int> query(int _x, int _y) {
Node *x = p[_x], *y = p[_y];
expose(y);
for (y = NULL; x != NULL; x = x->f) {
splay(x);
if (!(x->f)) {
ll e = x->v + (x->r ? x->r->e : 0LL) + (y ? y->e : 0LL);
int s = 1 + (x->r ? x->r->s : 0) + (y ? y->s : 0);
if (x->r && !y) {
e += x->r->rm;
e += (ll)x->r->s * x->v;
} else if (y && !(x->r)) {
e += y->rm;
e += (ll)y->s * x->v;
} else if (y && x->r) {
e += (ll)(x->r->s + 1) * y->rm;
e += (ll)(y->s + 1) * x->r->rm;
e += (ll)(x->r->s + 1) * (y->s + 1) * x->v - x->v;
}
return pair(e, s);
}
x->r = y;
update(y = x);
}
}

ll gcd(ll a, ll b) {
return !b ? a : gcd(b, a % b);
}

int main() {
#ifdef KANARI
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif

fread(buffer, sizeof(char), sizeof(char) * SIZE, stdin);

for (int i = 1; i <= n; ++i) a[i] = read();
for (int i = 1; i < n; ++i) {
}
for (int i = 1; i <= n; ++i) p[i] = new Node(a[i]);
build(1);

for (int i = 1; i <= n; ++i) sqr[i] = sqr[i - 1] + (ll)i * i;

while (m--) {
if (d == 1) {
if (x == y) continue;
if (!cut(x, y)) cut(y, x);
} else if (d == 2) {
if (!connected(x, y))
} else if (d == 3) {
if (connected(x, y))
modify(x, y, d);
} else {
if (!connected(x, y)) {
printf("-1\n");
continue;
}
pair <ll, int> ans = query(x, y);
ll e = ans.first, s = (ll)(ans.second + 1) * ans.second >> 1;
ll g = gcd(e, s);
printf("%lld/%lld\n", e / g, s / g);
}
}

return 0;
}