#include<bits/stdc++.h>
#define maxn 100010
#define ll long long
using namespace std;
int head[maxn], nxt[maxn * 2], a[maxn * 2], in[maxn], out[maxn];
int root, sj, id[maxn], edge, n, lg, jump[maxn][20], dep[maxn];
ll v[maxn], sum[maxn * 4], tag[maxn * 4];
int read()
{
	int tmp = 0, fh = 1; char c = getchar();
	while (c < '0' || c > '9')
	{
		if (c == '-') fh = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9')
	{
		tmp = tmp * 10 + c - '0';
		c = getchar();
	}
	return tmp * fh;
}
int get_jump(int u, int x)
{
	int t = lg;
	while (t != -1)
	{
		if (x >> t & 1) u = jump[u][t];
		t--;
	}
	return u;
}
void create(int u, int v)
{
	edge++; a[edge] = v; nxt[edge] = head[u]; head[u] = edge;
}
int contain(int u, int v)
{
	return in[v] >= in[u] && in[v] <= out[u];
}
void dfs(int u, int fa)
{
	in[u] = ++sj;
	id[sj] = u;
	jump[u][0] = fa; dep[u] = dep[fa] + 1;
	for (int i = head[u]; i; i = nxt[i])
	{
		int v = a[i];
		if (v != fa) dfs(v,u);
	}
	out[u] = sj;
}
void pushdown(int now, int l, int r)
{
	int mid = (l + r) / 2;
	if (tag[now])
	{
		tag[now * 2] += tag[now]; tag[now * 2 + 1] += tag[now];
		sum[now * 2] += tag[now] * (mid - l + 1);
		sum[now * 2 + 1] += tag[now] * (r - mid);
		tag[now] = 0;
	}
}
void build(int now, int l, int r)
{
	if (l == r) {sum[now] = v[id[l]]; return;}
	int mid = (l + r) / 2;
	build(now * 2, l, mid);
	build(now * 2 + 1, mid + 1, r);
	sum[now] = sum[now * 2] + sum[now * 2 + 1];
}
void change(int now, int l, int r, int left, int right, ll x)
{
	if (l == left && r == right)
	{
		sum[now] += (r - l + 1) * x;
		tag[now] += x;
		return;
	}
	pushdown(now, l, r);
	int mid = (l + r) / 2;
	if (left <= mid) change(now * 2, l, mid, left, min(right, mid), x);
	if (right >= mid + 1) change(now * 2 + 1, mid + 1, r, max(left, mid + 1), right, x);
	sum[now] = sum[now * 2] + sum[now * 2 + 1];
}
ll find(int now, int l, int r, int left, int right)
{
	if (l == left && r == right) return sum[now];
	pushdown(now, l, r);
	int mid = (l + r) / 2; ll ans = 0;
	if (left <= mid) ans = find(now * 2, l, mid, left, min(right, mid));
	if (right >= mid + 1) ans += find(now * 2 + 1, mid + 1, r, max(left, mid + 1), right);
	return ans;
}
void solve(int u)
{
	ll ans = 0;
	if (u == root) ans = sum[1];
	else if (contain(u, root))
	{
		int tmp = get_jump(root, dep[root] - dep[u] - 1);
		ans = sum[1] - find(1, 1, n, in[tmp], out[tmp]);
	}
	else ans = find(1, 1, n, in[u], out[u]);
	printf("%I64d\n", ans);
}
void modify(int u, ll x)
{
	if (u == root) change(1, 1, n, 1, n, x);
	else if (contain(u, root))
	{
		int tmp = get_jump(root, dep[root] - dep[u] - 1);
		if (in[tmp] != 1) change(1, 1, n, 1, in[tmp] - 1, x);
		if (out[tmp] != n) change(1, 1, n, out[tmp] + 1, n, x);
	}
	else change(1, 1, n, in[u], out[u], x);
}
int LCA(int u, int v)
{
	int t = lg;
	if (dep[u] < dep[v]) swap(u, v);
	while (dep[u] > dep[v])
	{
		if (dep[jump[u][t]] >= dep[v]) u = jump[u][t];
		t--;
	}
	if (u == v) return u;
	t = lg;
	while (true)
	{
		if (t == -1) return jump[u][0];
		if (jump[u][t] != jump[v][t])
		{
			u = jump[u][t];
			v = jump[v][t];
		}
		t--;
	}
}
int main()
{
//	freopen("E.in", "r", stdin);
//	freopen("E.out", "w", stdout);
	root = 1;
	int m;
	n = read(); m = read();
	for (int i = 1; i <= n; i++)
		v[i] = read();
	for (int i = 1; i <= n - 1; i++)
	{
		int u, v;
		u = read(); v = read();
		create(u, v); create(v, u);
	}
	dfs(1, 0);
	int now = 1;
	while (now < n) {now *= 2; lg++;}
	for (int j = 1; j <= lg; j++)
		for (int i = 1; i <= n; i++)
			jump[i][j] = jump[jump[i][j - 1]][j - 1];
	build(1, 1, n);
	while (m--)
	{
		int opt;
		opt = read();
		if (opt == 1)
		{
			int u;
			u = read();
			root = u;
		}
		if (opt == 2)
		{
			int u, v, lca;
			ll x;
			u = read(); v = read(); x = read();
			if (u == root) lca = u;
			else if (v == root) lca = v;
			else if (contain(u, v))
			{
				if (contain(u, root) && contain(root, v)) lca = root;
				else if (contain(v, root)) lca = root;
				else lca = u;
			}
			else if (contain(v, u))
			{
				if (contain(v, root) && contain(root, u)) lca = root;
				else if (contain(u, root)) lca = root;
				else lca = v;
			}
			else if (contain(v, root)) lca = v;
			else if (contain(u, root)) lca = u;
			else
			{
				lca = LCA(u, v);
				if (contain(lca, root) && (contain(root, u) || contain(root, v))) lca = root;
				else if (lca != root && contain(lca, root))
				{
					int tmp = get_jump(root, dep[root] - dep[lca] - 1);
					if (tmp == get_jump(u, dep[u] - dep[lca] - 1)) lca = tmp;
					else if (tmp == get_jump(v, dep[v] - dep[lca] - 1)) lca = tmp;
				}
			}
			modify(lca, x);
		}
		if (opt == 3)
		{
			int v;
			v = read();
			solve(v);
		}
	}
	return 0;
}


#include<bits/stdc++.h>
#define maxn 100010
#define ll long long
using namespace std;
int head[maxn], nxt[maxn * 2], a[maxn * 2], in[maxn], out[maxn];
int root, sj, id[maxn], edge, n, lg, jump[maxn][20], dep[maxn];
ll v[maxn], sum[maxn * 4], tag[maxn * 4];
int read()
{
	int tmp = 0, fh = 1; char c = getchar();
	while (c < '0' || c > '9')
	{
		if (c == '-') fh = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9')
	{
		tmp = tmp * 10 + c - '0';
		c = getchar();
	}
	return tmp * fh;
}
int get_jump(int u, int x)
{
	int t = lg;
	while (t != -1)
	{
		if (x >> t & 1) u = jump[u][t];
		t--;
	}
	return u;
}
void create(int u, int v)
{
	edge++; a[edge] = v; nxt[edge] = head[u]; head[u] = edge;
}
int contain(int u, int v)
{
	return in[v] >= in[u] && in[v] <= out[u];
}
void dfs(int u, int fa)
{
	in[u] = ++sj;
	id[sj] = u;
	jump[u][0] = fa; dep[u] = dep[fa] + 1;
	for (int i = head[u]; i; i = nxt[i])
	{
		int v = a[i];
		if (v != fa) dfs(v,u);
	}
	out[u] = sj;
}
void pushdown(int now, int l, int r)
{
	int mid = (l + r) / 2;
	if (tag[now])
	{
		tag[now * 2] += tag[now]; tag[now * 2 + 1] += tag[now];
		sum[now * 2] += tag[now] * (mid - l + 1);
		sum[now * 2 + 1] += tag[now] * (r - mid);
		tag[now] = 0;
	}
}
void build(int now, int l, int r)
{
	if (l == r) {sum[now] = v[id[l]]; return;}
	int mid = (l + r) / 2;
	build(now * 2, l, mid);
	build(now * 2 + 1, mid + 1, r);
	sum[now] = sum[now * 2] + sum[now * 2 + 1];
}
void change(int now, int l, int r, int left, int right, ll x)
{
	if (l == left && r == right)
	{
		sum[now] += (r - l + 1) * x;
		tag[now] += x;
		return;
	}
	pushdown(now, l, r);
	int mid = (l + r) / 2;
	if (left <= mid) change(now * 2, l, mid, left, min(right, mid), x);
	if (right >= mid + 1) change(now * 2 + 1, mid + 1, r, max(left, mid + 1), right, x);
	sum[now] = sum[now * 2] + sum[now * 2 + 1];
}
ll find(int now, int l, int r, int left, int right)
{
	if (l == left && r == right) return sum[now];
	pushdown(now, l, r);
	int mid = (l + r) / 2; ll ans = 0;
	if (left <= mid) ans = find(now * 2, l, mid, left, min(right, mid));
	if (right >= mid + 1) ans += find(now * 2 + 1, mid + 1, r, max(left, mid + 1), right);
	return ans;
}
void solve(int u)
{
	ll ans = 0;
	if (u == root) ans = sum[1];
	else if (contain(u, root))
	{
		int tmp = get_jump(root, dep[root] - dep[u] - 1);
		ans = sum[1] - find(1, 1, n, in[tmp], out[tmp]);
	}
	else ans = find(1, 1, n, in[u], out[u]);
	printf("%I64d\n", ans);
}
void modify(int u, ll x)
{
	if (u == root) change(1, 1, n, 1, n, x);
	else if (contain(u, root))
	{
		int tmp = get_jump(root, dep[root] - dep[u] - 1);
		if (in[tmp] != 1) change(1, 1, n, 1, in[tmp] - 1, x);
		if (out[tmp] != n) change(1, 1, n, out[tmp] + 1, n, x);
	}
	else change(1, 1, n, in[u], out[u], x);
}
int LCA(int u, int v)
{
	int t = lg;
	if (dep[u] < dep[v]) swap(u, v);
	while (dep[u] > dep[v])
	{
		if (dep[jump[u][t]] >= dep[v]) u = jump[u][t];
		t--;
	}
	if (u == v) return u;
	t = lg;
	while (true)
	{
		if (t == -1) return jump[u][0];
		if (jump[u][t] != jump[v][t])
		{
			u = jump[u][t];
			v = jump[v][t];
		}
		t--;
	}
}
int main()
{
//	freopen("E.in", "r", stdin);
//	freopen("E.out", "w", stdout);
	root = 1;
	int m;
	n = read(); m = read();
	for (int i = 1; i <= n; i++)
		v[i] = read();
	for (int i = 1; i <= n - 1; i++)
	{
		int u, v;
		u = read(); v = read();
		create(u, v); create(v, u);
	}
	dfs(1, 0);
	int now = 1;
	while (now < n) {now *= 2; lg++;}
	for (int j = 1; j <= lg; j++)
		for (int i = 1; i <= n; i++)
			jump[i][j] = jump[jump[i][j - 1]][j - 1];
	build(1, 1, n);
	while (m--)
	{
		int opt;
		opt = read();
		if (opt == 1)
		{
			int u;
			u = read();
			root = u;
		}
		if (opt == 2)
		{
			int u, v, lca;
			ll x;
			u = read(); v = read(); x = read();
			if (u == root) lca = u;
			else if (v == root) lca = v;
			else if (contain(u, root) && contain(root, v)) lca = root;
			else if (contain(u, v) && contain(v, root)) lca = v;
			else if (contain(root, u) && contain(u, v)) lca = u;
			else if (contain(root, v) && contain(v, u)) lca = v;
			else if (contain(v, u) && contain(u, root)) lca = u;
			else if (contain(v, root) && contain(root, u)) lca = root;
			else if (contain(u, root)) lca = u;
			else if (contain(v, root)) lca = v;
			else
			{
				lca = LCA(u, v);
				if (contain(lca, root) && (contain(root, u) || contain(root, v))) lca = root;
				else
				if (lca != root && contain(lca, root))
				{
					int tmp = get_jump(root, dep[root] - dep[lca] - 1);
					if (tmp == get_jump(u, dep[u] - dep[lca] - 1)) lca = tmp;
					else if (tmp == get_jump(v, dep[v] - dep[lca] - 1)) lca = tmp;
				}
			}
			modify(lca, x);
		}
		if (opt == 3)
		{
			int v;
			v = read();
			solve(v);
		}
	}
	return 0;
}


#include <bits/stdc++.h>
#define F(i, l, r) for(int i = (l), _end_ = (int)(r); i <= _end_; ++i)
#define f(i, r, l) for(int i = (r), _end_ = (int)(l); i >= _end_; --i)
#define Set(a, v) memset(a, v, sizeof(a))
#define file(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
using namespace std;

bool chkmin(int &a, int b) {return b < a ? a = b, 1 : 0;}
bool chkmax(int &a, int b) {return b > a ? a = b, 1 : 0;}

inline int read() {
 int x = 0, fh = 1; char ch = getchar();
    for (; !isdigit(ch); ch = getchar() ) if (ch == '-') fh = -1;
    for (; isdigit(ch); ch = getchar() ) x = (x<<1) + (x<<3) + (ch ^ '0');
    return x * fh;
}
int n,q;
int val[600005],cnt;
int he[600005],to[600005],ne[600005],e;
void add(int x,int y){
    to[++e]=y;
	ne[e]=he[x];
	he[x]=e;
}
	int fa[300005][20],dep[300005];
	int L[300005],R[300005];
	long long addv[1200005], sum[1200005];

	#define lc (o << 1)
	#define rc (o << 1 | 1)
	#define M ((L + R) >> 1)

	void built(int o, int L, int R) {
		if(L == R) sum[o] = val[L];
		else built(lc, L, M), built(rc, M + 1, R), sum[o] = sum[lc] + sum[rc];
	}

	void update(int o, int L, int R, int l, int r, long long w) {
		if(l<=L&&R<=r)addv[o] += w, sum[o] += (R - L + 1) * w;
		else {
			sum[o] += w * (min(R,r)-max(L,l) + 1);
			if (l<=M)update(lc,L,M,l,r,w);
			if (r>M)update(rc,M+1,R,l,r,w);
		}
	}

	long long query(int o,int L,int R,int l,int r){
		if(l<=L&&R<=r)return sum[o];
		else{
			long long ret=addv[o]*(min(R,r)-max(L,l)+1);
			if(l<=M)ret+=query(lc,L,M,l,r);
			if(r>M)ret+=query(rc,M + 1,R,l,r);
			return ret;
		}
	}

void dfs(int x){
   L[x]=++cnt;
   for(int i=he[x];i;i=ne[i]){
       int v=to[i];
	   if(v==fa[x][0])continue;
	   fa[v][0]=x;
	   dep[v]=dep[x]+1;
	   F(i,1,18)fa[v][i]=fa[fa[v][i-1]][i-1];
	   dfs(v);
   }
   R[x]=cnt;
}
int  find(int u,int v){
    for(int i=18;i>=0&&v;i--){
	   if(v&(1<<i)){
	     u=fa[u][i];
	   }
	}
	return u;
}
int lca(int u,int v){
     if(dep[u]<dep[v]){
	     swap(u,v);
	 }
	 u=find(u,dep[u]-dep[v]);
	 if(u==v)return u;
	 f(i,18,0){
	    if(fa[u][i]^fa[v][i]){
		   u=fa[u][i];
		   v=fa[v][i];
		}
	 }
	 return fa[u][0];
}
int getch(int u,int v){return find(u,dep[u]-dep[v]-1);}
int main () {
#ifndef ONLINE_JUDGE
file("tree");
#endif
    n=read();
	q=read();
	F(i,1,n){
	   val[i+n]=read();
	}
	F(i,1,n-1){
	    int x=read(),y=read();
		add(x,y);
		add(y,x);
	}
	int rt=1;
	dfs(1);
	F(i,1,n)val[L[i]]=val[i+n];
	built(1,1,n);
    while(q--){
	   int opt=read();
	   if(opt==1)rt=read();
	   if(opt==2){
	      int u=read(),v=read(),x=read();
		   int o=lca(u,v);
		   if(L[o]<=L[rt]&&L[rt]<=R[o]){
		   int xx=lca(u,rt),yy=lca(v,rt);
		   update(1,1,n,1,n,x);
		   if(xx!=rt&&yy!=rt){
		       if(dep[xx]<dep[yy])swap(xx,yy);
			   xx=getch(rt,xx);
			   update(1,1,n,L[xx],R[xx],-x);
		   }
		   }
		   else update(1,1,n,L[o],R[o],x);
	   }
	   if(opt==3){
	      int u=read();
		  long long ans=0;
		  if(L[u]<=L[rt]&&L[rt]<=R[u]){
		     ans+=query(1,1,n,1,n);
			 if(u!=rt){
			     int o=getch(rt,u);
				 ans-=query(1,1,n,L[o],R[o]);
			 }
		  }
		  else ans=query(1,1,n,L[u],R[u]);
		  printf("%lld\n",ans);
	   }
	}
	return 0;
}


#include <stdio.h>
#define ll long long
ll he[400010],ld[400010],sz[100010];
int sd[100010],top[100010],son[100010],fa[100010],n;
int sr[100010];
void pu(int i)
{
	he[i]=he[i<<1]+he[(i<<1)|1];
}
void pd(int i,int l,int r)
{
	int m=(l+r)>>1;
	ld[i<<1]+=ld[i];
	ld[(i<<1)|1]+=ld[i];
	he[i<<1]+=ld[i]*(m-l);
	he[(i<<1)|1]+=ld[i]*(r-m);
	ld[i]=0;
}
void jianshu(int i,int l,int r)
{
	if(l+1==r)
	{
		he[i]=sz[l];
		return;
	}
	int m=(l+r)>>1;
	jianshu(i<<1,l,m);
	jianshu((i<<1)|1,m,r);
	pu(i);
}
void xiugai(int i,int l,int r,int L,int R,ll x)
{
	if(r<=L||R<=l)
		return;
	if(L<=l&&r<=R)
	{
		ld[i]+=x;
		he[i]+=(r-l)*x;
		return;
	}
	pd(i,l,r);
	int m=(l+r)>>1;
	xiugai(i<<1,l,m,L,R,x);
	xiugai((i<<1)|1,m,r,L,R,x);
	pu(i);
}
ll sum(int i,int l,int r,int L,int R)
{
	if(r<=L||R<=l)
		return 0;
	if(L<=l&&r<=R)
		return he[i];
	pd(i,l,r);
	int m=(l+r)>>1;
	return sum(i<<1,l,m,L,R)+sum((i<<1)|1,m,r,L,R);
}
int fr[100010],ne[200010];
int v[200010],bs=0;
int bz[17][100010];
int xl[100010],xr[100010],tm=0;
void addb(int a,int b)
{
	v[bs]=b;
	ne[bs]=fr[a];
	fr[a]=bs;
	bs+=1;
}
int dfs1(int u,int f)
{
	xl[u]=tm++;
	sd[u]=sd[f]+1;
	fa[u]=f;
	bz[0][u]=f;
	int rtn=1,ma=-1;
	son[u]=-1;
	for(int i=fr[u];i!=-1;i=ne[i])
	{
		if(v[i]!=f)
		{
			int t=dfs1(v[i],u);
			rtn+=t;
			if(t>ma)
			{
				ma=t;
				son[u]=v[i];
			}
		}
	}
	xr[u]=tm;
	return rtn;
}
void dfs2(int u,int f,int tp)
{
	top[u]=tp;
	if(son[u]==-1)
		return;
	dfs2(son[u],u,tp);
	for(int i=fr[u];i!=-1;i=ne[i])
	{
		if(v[i]!=f&&v[i]!=son[u])
			dfs2(v[i],u,v[i]);
	}
}
int getlca(int x,int y)
{
	while(top[x]!=top[y])
	{
		if(sd[top[x]]<sd[top[y]])
		{
			int t=x;
			x=y;
			y=t;
		}
		x=fa[top[x]];
	}
	if(sd[x]<sd[y])
		return x;
	else
		return y;
}
void ycl()
{
	dfs1(1,1),dfs2(1,1,1);
	for(int i=1;i<=16;i++)
	{
		for(int j=1;j<=n;j++)
			bz[i][j]=bz[i-1][bz[i-1][j]];
	}
	for(int i=1;i<=n;i++)
		sz[xl[i]]=sr[i];
	jianshu(1,0,n);
}
int getv(int x,int y)
{
	for(int i=16;i>=0;i--)
	{
		if(sd[bz[i][y]]>sd[x])
			y=bz[i][y];
	}
	return y;
}
void add(int u,int x)
{
	xiugai(1,0,n,xl[u],xr[u],x);
}
ll getsum(int u)
{
	return sum(1,0,n,xl[u],xr[u]);
}
int main()
{
	int m,g=1;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&sr[i]);
		fr[i]=-1;
	}
	for(int i=0;i<n-1;i++)
	{
		int a,b;
		scanf("%d%d",&a,&b);
		addb(a,b);
		addb(b,a);
	}
	ycl();
	for(int i=0;i<m;i++)
	{
		int lx;
		scanf("%d",&lx);
		if(lx==1)
		{
			int a;
			scanf("%d",&a);
			g=a;
		}
		else if(lx==2)
		{
			int u,v,x;
			scanf("%d%d%d",&u,&v,&x);
			int l1=getlca(u,g),l2=getlca(v,g),l3=getlca(u,v);
			if(sd[l2]>sd[l1])
				l1=l2;
			if(sd[l3]>sd[l1])
				l1=l3;
			int t=getlca(g,l1);
			if(t==l1)
			{
				add(1,x);
				int q=getv(t,g);
				if(q!=t)
					add(q,-x);
			}
			else
				add(l1,x);
		}
		else
		{
			int l1;
			scanf("%d",&l1);
			int t=getlca(g,l1);
			if(t==l1)
			{
				int q=getv(t,g);
				if(q==t)
					printf("%lld\n",getsum(1));
				else
					printf("%lld\n",getsum(1)-getsum(q));
			}
			else
				printf("%lld\n",getsum(l1));
		}
	}
	return 0;
}


#include <stdio.h>
#define ll long long
ll he[400010],ld[400010],sz[100010];
int sd[100010],top[100010],son[100010],fa[100010],n;
int sr[100010];
void pu(int i)
{
	he[i]=he[i<<1]+he[(i<<1)|1];
}
void pd(int i,int l,int r)
{
	int m=(l+r)>>1;
	ld[i<<1]+=ld[i];
	ld[(i<<1)|1]+=ld[i];
	he[i<<1]+=ld[i]*(m-l);
	he[(i<<1)|1]+=ld[i]*(r-m);
	ld[i]=0;
}
void jianshu(int i,int l,int r)
{
	if(l+1==r)
	{
		he[i]=sz[l];
		return;
	}
	int m=(l+r)>>1;
	jianshu(i<<1,l,m);
	jianshu((i<<1)|1,m,r);
	pu(i);
}
void xiugai(int i,int l,int r,int L,int R,ll x)
{
	if(r<=L||R<=l)
		return;
	if(L<=l&&r<=R)
	{
		ld[i]+=x;
		he[i]+=(r-l)*x;
		return;
	}
	pd(i,l,r);
	int m=(l+r)>>1;
	xiugai(i<<1,l,m,L,R,x);
	xiugai((i<<1)|1,m,r,L,R,x);
	pu(i);
}
ll sum(int i,int l,int r,int L,int R)
{
	if(r<=L||R<=l)
		return 0;
	if(L<=l&&r<=R)
		return he[i];
	pd(i,l,r);
	int m=(l+r)>>1;
	return sum(i<<1,l,m,L,R)+sum((i<<1)|1,m,r,L,R);
}
int fr[100010],ne[200010];
int v[200010],bs=0;
int bz[17][100010];
int xl[100010],xr[100010],tm=0;
void addb(int a,int b)
{
	v[bs]=b;
	ne[bs]=fr[a];
	fr[a]=bs;
	bs+=1;
}
int dfs1(int u,int f)
{
	xl[u]=tm++;
	sd[u]=sd[f]+1;
	fa[u]=f;
	bz[0][u]=f;
	int rtn=1,ma=-1;
	son[u]=-1;
	for(int i=fr[u];i!=-1;i=ne[i])
	{
		if(v[i]!=f)
		{
			int t=dfs1(v[i],u);
			rtn+=t;
			if(t>ma)
			{
				ma=t;
				son[u]=v[i];
			}
		}
	}
	xr[u]=tm;
	return rtn;
}
void dfs2(int u,int f,int tp)
{
	top[u]=tp;
	if(son[u]==-1)
		return;
	dfs2(son[u],u,tp);
	for(int i=fr[u];i!=-1;i=ne[i])
	{
		if(v[i]!=f&&v[i]!=son[u])
			dfs2(v[i],u,v[i]);
	}
}
int getlca(int x,int y)
{
	while(top[x]!=top[y])
	{
		if(sd[top[x]]<sd[top[y]])
		{
			int t=x;
			x=y;
			y=t;
		}
		x=fa[top[x]];
	}
	if(sd[x]<sd[y])
		return x;
	else
		return y;
}
void ycl()
{
	dfs1(1,1),dfs2(1,1,1);
	for(int i=1;i<=16;i++)
	{
		for(int j=1;j<=n;j++)
			bz[i][j]=bz[i-1][bz[i-1][j]];
	}
	for(int i=1;i<=n;i++)
		sz[xl[i]]=sr[i];
	jianshu(1,0,n);
}
int getv(int x,int y)
{
	for(int i=16;i>=0;i--)
	{
		if(sd[bz[i][y]]>sd[x])
			y=bz[i][y];
	}
	return y;
}
void add(int u,int x)
{
	xiugai(1,0,n,xl[u],xr[u],x);
}
ll getsum(int u)
{
	return sum(1,0,n,xl[u],xr[u]);
}
int main()
{
	int m,g=1;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&sr[i]);
		fr[i]=-1;
	}
	for(int i=0;i<n-1;i++)
	{
		int a,b;
		scanf("%d%d",&a,&b);
		addb(a,b);
		addb(b,a);
	}
	ycl();
	for(int i=0;i<m;i++)
	{
		int lx;
		scanf("%d",&lx);
		if(lx==1)
		{
			int a;
			scanf("%d",&a);
			g=a;
		}
		else if(lx==2)
		{
			int u,v,x;
			scanf("%d%d%d",&u,&v,&x);
			int l1=getlca(u,g),l2=getlca(v,g),l3=getlca(u,v);
			if(sd[l2]>sd[l1])
				l1=l2;
			if(sd[l3]>sd[l1])
				l1=l3;
			int t=getlca(g,l1);
			if(t==l1)
			{
				add(1,x);
				int q=getv(t,g);
				if(q!=t)
					add(q,-x);
			}
			else
				add(l1,x);
		}
		else
		{
			int l1;
			scanf("%d",&l1);
			int t=getlca(g,l1);
			if(t==g||t!=l1)
				printf("%lld\n",getsum(l1));
			else
			{
				int q=getv(t,g);
				if(q==t)
					printf("%lld\n",getsum(1));
				else
					printf("%lld\n",getsum(1)-getsum(q));
			}
		}
	}
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define maxn 100001
long long a[maxn];int n,m;int root;
int head[maxn],ver[maxn<<1],nxt[maxn<<1],tot;
inline void addedge(int a,int b)
{
	nxt[++tot]=head[a];ver[tot]=b;head[a]=tot;
	nxt[++tot]=head[b];ver[tot]=a;head[b]=tot;
}
int size[maxn],hson[maxn],fa[maxn],dep[maxn];
int Fa[maxn][23];
inline void dfs1(int x,int fat)
{
	size[x]=1;fa[x]=fat;dep[x]=dep[fat]+1;Fa[x][0]=fat;
	int maxsize=0;
	for(int i=head[x];i;i=nxt[i])
	{
		int y=ver[i];if(y==fat) continue;
		dfs1(y,x);size[x]+=size[y];
		if(size[y]>maxsize) maxsize=size[y],hson[x]=y;
	}
}
int top[maxn],id[maxn],rid[maxn],id_cnt;
inline void dfs2(int x,int Top)
{
	top[x]=Top;id[x]=++id_cnt;rid[id_cnt]=x;
	if(hson[x]) dfs2(hson[x],Top);
	for(int i=head[x];i;i=nxt[i])
	{
		int y=ver[i];if(y==fa[x]||y==hson[x]) continue;
		dfs2(y,y);
	}
}
struct segment_tree
{
	#define lson(x) (x<<1)
	#define rson(x) (x<<1|1)
	long long sumv[maxn<<2],addv[maxn<<2];
	inline void pushup(int p){sumv[p]=sumv[lson(p)]+sumv[rson(p)];}
	inline void build(int p,int l,int r)
	{
		if(l==r) return (void)(sumv[p]=a[rid[l]]);
		int mid=(l+r)>>1;
		build(lson(p),l,mid);build(rson(p),mid+1,r);
		pushup(p);
	}
	inline void setadd(int p,int l,int r,int Add)
	{
		addv[p]+=Add;
		sumv[p]+=Add*(r-l+1);
	}
	inline void pushdown(int p,int l,int r)
	{
		if(addv[p]==0) return;int mid=(l+r)>>1;
		setadd(lson(p),l,mid,addv[p]);
		setadd(rson(p),mid+1,r,addv[p]);
		addv[p]=0;
	}
	inline void add(int p,int l,int r,int ql,int qr,int Add)
	{
		if(ql<=l&&qr>=r) return (void)setadd(p,l,r,Add);
		int mid=(l+r)>>1;pushdown(p,l,r);
		if(ql<=mid) add(lson(p),l,mid,ql,qr,Add);
		if(qr>mid) add(rson(p),mid+1,r,ql,qr,Add);
		pushup(p);
	}
	inline int Qsum(int p,int l,int r,int ql,int qr)
	{
		if(ql<=l&&qr>=r) return sumv[p];
		int mid=(l+r)>>1,res=0;pushdown(p,l,r);
		if(ql<=mid) res+=Qsum(lson(p),l,mid,ql,qr);
		if(qr>mid) res+=Qsum(rson(p),mid+1,r,ql,qr);
		return res;
	}
}seg;
inline void init()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%lld",a+i);
	for(int i=1,a,b;i<n;i++) scanf("%d%d",&a,&b),addedge(a,b);
	dfs1(1,0);dfs2(1,1);
	seg.build(1,1,n);root=1;
	for(int j=1;j<=20;j++) for(int i=1;i<=n;i++) Fa[i][j]=Fa[Fa[i][j-1]][j-1];
}
inline int lca(int a,int b)
{
	while(top[a]!=top[b])
	{
		if(dep[top[a]]<dep[top[b]]) swap(a,b);
		a=fa[top[a]];
	}
	if(dep[a]>dep[b]) swap(a,b);
	return a;
}
inline int getlca(int a,int b)
{
	if(a==b) return a;
	int A=lca(a,b),B=lca(a,root),C=lca(b,root);
	int Mindep=0,ans=-1;
	if(dep[A]>Mindep) Mindep=dep[A],ans=A;
	if(dep[B]>Mindep) Mindep=dep[B],ans=B;
	if(dep[C]>Mindep) Mindep=dep[C],ans=C;
	return ans;
}
inline int RUN(int from,int to)
{
	int Dep=dep[from]-dep[to]-1;
	for(int i=20;i;i--) if(Dep&(1<<i)) from=Fa[from][i];
	return from;
}
inline void add_subtree(int x,int Add)
{
	if(x==root) return (void)seg.add(1,1,n,1,n,Add);
	int L=id[x],R=id[x]+size[x]-1;
	if(id[root]<L||id[root]>R) return (void)seg.add(1,1,n,L,R,Add);
	int Sub=RUN(root,x);
	L=id[Sub];R=id[Sub]+size[Sub]-1;
	if(L>1) seg.add(1,1,n,1,L-1,Add);if(R<n) seg.add(1,1,n,R+1,n,Add);
}
inline int Qsubtree(int x)
{
	if(x==root) return seg.Qsum(1,1,n,1,n);
	int L=id[x],R=id[x]+size[x]-1;
	if(id[root]<L||id[root]>R) return seg.Qsum(1,1,n,L,R);
	int Sub=RUN(root,x);
	L=id[Sub];R=id[Sub]+size[Sub]-1;int ans=0;
	if(L>1) ans+=seg.Qsum(1,1,n,1,L-1);if(R<n) ans+=seg.Qsum(1,1,n,R+1,n);
	return ans;
}
int main()
{
	init();int a,b,c,d;
	while(m--)
	{
		scanf("%d",&a);
		if(a==1) scanf("%d",&root);
		if(a==2) scanf("%d%d%d",&b,&c,&d),add_subtree(getlca(b,c),d);
		if(a==3) scanf("%d",&b),printf("%d\n",Qsubtree(b));
	}
}


#include<bits/stdc++.h>
using namespace std;
#define maxn 100001
long long a[maxn];int n,m;int root;
int head[maxn],ver[maxn<<1],nxt[maxn<<1],tot;
inline void addedge(int a,int b)
{
	nxt[++tot]=head[a];ver[tot]=b;head[a]=tot;
	nxt[++tot]=head[b];ver[tot]=a;head[b]=tot;
}
int size[maxn],hson[maxn],fa[maxn],dep[maxn];
int Fa[maxn][23];
inline void dfs1(int x,int fat)
{
	size[x]=1;fa[x]=fat;dep[x]=dep[fat]+1;Fa[x][0]=fat;
	int maxsize=0;
	for(int i=head[x];i;i=nxt[i])
	{
		int y=ver[i];if(y==fat) continue;
		dfs1(y,x);size[x]+=size[y];
		if(size[y]>maxsize) maxsize=size[y],hson[x]=y;
	}
}
int top[maxn],id[maxn],rid[maxn],id_cnt;
inline void dfs2(int x,int Top)
{
	top[x]=Top;id[x]=++id_cnt;rid[id_cnt]=x;
	if(hson[x]) dfs2(hson[x],Top);
	for(int i=head[x];i;i=nxt[i])
	{
		int y=ver[i];if(y==fa[x]||y==hson[x]) continue;
		dfs2(y,y);
	}
}
struct segment_tree
{
	#define lson(x) (x<<1)
	#define rson(x) (x<<1|1)
	long long sumv[maxn<<2],addv[maxn<<2];
	inline void pushup(int p){sumv[p]=sumv[lson(p)]+sumv[rson(p)];}
	inline void build(int p,int l,int r)
	{
		if(l==r) return (void)(sumv[p]=a[rid[l]]);
		int mid=(l+r)>>1;
		build(lson(p),l,mid);build(rson(p),mid+1,r);
		pushup(p);
	}
	inline void setadd(int p,int l,int r,int Add)
	{
		addv[p]+=Add;
		sumv[p]+=Add*(r-l+1);
	}
	inline void pushdown(int p,int l,int r)
	{
		if(addv[p]==0) return;int mid=(l+r)>>1;
		setadd(lson(p),l,mid,addv[p]);
		setadd(rson(p),mid+1,r,addv[p]);
		addv[p]=0;
	}
	inline void add(int p,int l,int r,int ql,int qr,int Add)
	{
		if(ql<=l&&qr>=r) return (void)setadd(p,l,r,Add);
		int mid=(l+r)>>1;pushdown(p,l,r);
		if(ql<=mid) add(lson(p),l,mid,ql,qr,Add);
		if(qr>mid) add(rson(p),mid+1,r,ql,qr,Add);
		pushup(p);
	}
	inline int Qsum(int p,int l,int r,int ql,int qr)
	{
		if(ql<=l&&qr>=r) return sumv[p];
		int mid=(l+r)>>1,res=0;pushdown(p,l,r);
		if(ql<=mid) res+=Qsum(lson(p),l,mid,ql,qr);
		if(qr>mid) res+=Qsum(rson(p),mid+1,r,ql,qr);
		return res;
	}
}seg;
inline void init()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%lld",a+i);
	for(int i=1,a,b;i<n;i++) scanf("%d%d",&a,&b),addedge(a,b);
	dfs1(1,0);dfs2(1,1);
	seg.build(1,1,n);root=1;
	for(int j=1;j<=20;j++) for(int i=1;i<=n;i++) Fa[i][j]=Fa[Fa[i][j-1]][j-1];
}
inline int lca(int a,int b)
{
	while(top[a]!=top[b])
	{
		if(dep[top[a]]<dep[top[b]]) swap(a,b);
		a=fa[top[a]];
	}
	if(dep[a]>dep[b]) swap(a,b);
	return a;
}
inline int getlca(int a,int b)
{
	if(a==b) return a;
	int A=lca(a,b),B=lca(a,root),C=lca(b,root);
	int Mindep=0,ans=-1;
	if(dep[A]>Mindep) Mindep=dep[A],ans=A;
	if(dep[B]>Mindep) Mindep=dep[B],ans=B;
	if(dep[C]>Mindep) Mindep=dep[C],ans=C;
	return ans;
}
inline int RUN(int from,int to)
{
	int Dep=dep[from]-dep[to]-1;
	for(int i=20;i>=0;i--) if(Dep&(1<<i)) from=Fa[from][i];
	return from;
}
inline void add_subtree(int x,int Add)
{
	if(x==root) return (void)seg.add(1,1,n,1,n,Add);
	int L=id[x],R=id[x]+size[x]-1;
	if(id[root]<L||id[root]>R) return (void)seg.add(1,1,n,L,R,Add);
	int Sub=RUN(root,x);
	L=id[Sub];R=id[Sub]+size[Sub]-1;
	if(L>1) seg.add(1,1,n,1,L-1,Add);if(R<n) seg.add(1,1,n,R+1,n,Add);
}
inline int Qsubtree(int x)
{
	if(x==root) return seg.Qsum(1,1,n,1,n);
	int L=id[x],R=id[x]+size[x]-1;
	if(id[root]<L||id[root]>R) return seg.Qsum(1,1,n,L,R);
	int Sub=RUN(root,x);
	L=id[Sub];R=id[Sub]+size[Sub]-1;int ans=0;
	if(L>1) ans+=seg.Qsum(1,1,n,1,L-1);if(R<n) ans+=seg.Qsum(1,1,n,R+1,n);
	return ans;
}
int main()
{
	init();int a,b,c,d;//for(int i=1;i<=n;i++) cout<<fa[i]<<' ';putchar('\n');
//	while(cin>>a>>b) cout<<RUN(a,b)<<endl;
	while(m--)
	{
		scanf("%d",&a);
		if(a==1) scanf("%d",&root);
		if(a==2) scanf("%d%d%d",&b,&c,&d),add_subtree(getlca(b,c),d);
		if(a==3) scanf("%d",&b),printf("%d\n",Qsubtree(b));
	}
}
/*
6 1000
1 4 2 8 5 7
1 2
3 1
4 3
4 5
3 6
3 1
2 4 6 3
3 4
1 6
2 2 4 -5
1 4
3 3
3 2
3 3
3 1
3 6
*///fd1a4f5dsa4f64d5sa7g8b7


#include<bits/stdc++.h>
using namespace std;
#define maxn 100001
#define int long long
long long a[maxn];int n,m;int root;
int head[maxn],ver[maxn<<1],nxt[maxn<<1],tot;
inline void addedge(int a,int b)
{
	nxt[++tot]=head[a];ver[tot]=b;head[a]=tot;
	nxt[++tot]=head[b];ver[tot]=a;head[b]=tot;
}
int size[maxn],hson[maxn],fa[maxn],dep[maxn];
int Fa[maxn][23];
inline void dfs1(int x,int fat)
{
	size[x]=1;fa[x]=fat;dep[x]=dep[fat]+1;Fa[x][0]=fat;
	int maxsize=0;
	for(int i=head[x];i;i=nxt[i])
	{
		int y=ver[i];if(y==fat) continue;
		dfs1(y,x);size[x]+=size[y];
		if(size[y]>maxsize) maxsize=size[y],hson[x]=y;
	}
}
int top[maxn],id[maxn],rid[maxn],id_cnt;
inline void dfs2(int x,int Top)
{
	top[x]=Top;id[x]=++id_cnt;rid[id_cnt]=x;
	if(hson[x]) dfs2(hson[x],Top);
	for(int i=head[x];i;i=nxt[i])
	{
		int y=ver[i];if(y==fa[x]||y==hson[x]) continue;
		dfs2(y,y);
	}
}
struct segment_tree
{
	#define lson(x) (x<<1)
	#define rson(x) (x<<1|1)
	long long sumv[maxn<<2],addv[maxn<<2];
	inline void pushup(int p){sumv[p]=sumv[lson(p)]+sumv[rson(p)];}
	inline void build(int p,int l,int r)
	{
		if(l==r) return (void)(sumv[p]=a[rid[l]]);
		int mid=(l+r)>>1;
		build(lson(p),l,mid);build(rson(p),mid+1,r);
		pushup(p);
	}
	inline void setadd(int p,int l,int r,int Add)
	{
		addv[p]+=Add;
		sumv[p]+=Add*(r-l+1);
	}
	inline void pushdown(int p,int l,int r)
	{
		if(addv[p]==0) return;int mid=(l+r)>>1;
		setadd(lson(p),l,mid,addv[p]);
		setadd(rson(p),mid+1,r,addv[p]);
		addv[p]=0;
	}
	inline void add(int p,int l,int r,int ql,int qr,int Add)
	{
		if(ql<=l&&qr>=r) return (void)setadd(p,l,r,Add);
		int mid=(l+r)>>1;pushdown(p,l,r);
		if(ql<=mid) add(lson(p),l,mid,ql,qr,Add);
		if(qr>mid) add(rson(p),mid+1,r,ql,qr,Add);
		pushup(p);
	}
	inline int Qsum(int p,int l,int r,int ql,int qr)
	{
		if(ql<=l&&qr>=r) return sumv[p];
		int mid=(l+r)>>1,res=0;pushdown(p,l,r);
		if(ql<=mid) res+=Qsum(lson(p),l,mid,ql,qr);
		if(qr>mid) res+=Qsum(rson(p),mid+1,r,ql,qr);
		return res;
	}
}seg;
inline void init()
{
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;i++) scanf("%lld",a+i);
	for(int i=1,a,b;i<n;i++) scanf("%lld%lld",&a,&b),addedge(a,b);
	dfs1(1,0);dfs2(1,1);
	seg.build(1,1,n);root=1;
	for(int j=1;j<=20;j++) for(int i=1;i<=n;i++) Fa[i][j]=Fa[Fa[i][j-1]][j-1];
}
inline int lca(int a,int b)
{
	while(top[a]!=top[b])
	{
		if(dep[top[a]]<dep[top[b]]) swap(a,b);
		a=fa[top[a]];
	}
	if(dep[a]>dep[b]) swap(a,b);
	return a;
}
inline int getlca(int a,int b)
{
	if(a==b) return a;
	int A=lca(a,b),B=lca(a,root),C=lca(b,root);
	int Mindep=0,ans=-1;
	if(dep[A]>Mindep) Mindep=dep[A],ans=A;
	if(dep[B]>Mindep) Mindep=dep[B],ans=B;
	if(dep[C]>Mindep) Mindep=dep[C],ans=C;
	return ans;
}
inline int RUN(int from,int to)
{
	int Dep=dep[from]-dep[to]-1;
	for(int i=20;i>=0;i--) if(Dep&(1<<i)) from=Fa[from][i];
	return from;
}
inline void add_subtree(int x,int Add)
{
	if(x==root) return (void)seg.add(1,1,n,1,n,Add);
	int L=id[x],R=id[x]+size[x]-1;
	if(id[root]<L||id[root]>R) return (void)seg.add(1,1,n,L,R,Add);
	int Sub=RUN(root,x);
	L=id[Sub];R=id[Sub]+size[Sub]-1;
	if(L>1) seg.add(1,1,n,1,L-1,Add);if(R<n) seg.add(1,1,n,R+1,n,Add);
}
inline int Qsubtree(int x)
{
	if(x==root) return seg.Qsum(1,1,n,1,n);
	int L=id[x],R=id[x]+size[x]-1;
	if(id[root]<L||id[root]>R) return seg.Qsum(1,1,n,L,R);
	int Sub=RUN(root,x);
	L=id[Sub];R=id[Sub]+size[Sub]-1;int ans=0;
	if(L>1) ans+=seg.Qsum(1,1,n,1,L-1);if(R<n) ans+=seg.Qsum(1,1,n,R+1,n);
	return ans;
}
signed main()
{
	init();int a,b,c,d;
	while(m--)
	{
		scanf("%lld",&a);
		if(a==1) scanf("%lld",&root);
		if(a==2) scanf("%lld%lld%lld",&b,&c,&d),add_subtree(getlca(b,c),d);
		if(a==3) scanf("%lld",&b),printf("%lld\n",Qsubtree(b));
	}
}//fcyakking


#include<bits/stdc++.h>
using namespace std;
#define maxn 100001
#define int long long
long long a[maxn];int n,m;int root;
int head[maxn],ver[maxn<<1],nxt[maxn<<1],tot;
inline void addedge(int a,int b)
{
	nxt[++tot]=head[a];ver[tot]=b;head[a]=tot;
	nxt[++tot]=head[b];ver[tot]=a;head[b]=tot;
}
int size[maxn],hson[maxn],fa[maxn],dep[maxn];
int Fa[maxn][23];
inline void dfs1(int x,int fat)
{
	size[x]=1;fa[x]=fat;dep[x]=dep[fat]+1;Fa[x][0]=fat;
	int maxsize=0;
	for(int i=head[x];i;i=nxt[i])
	{
		int y=ver[i];if(y==fat) continue;
		dfs1(y,x);size[x]+=size[y];
		if(size[y]>maxsize) maxsize=size[y],hson[x]=y;
	}
}
int top[maxn],id[maxn],rid[maxn],id_cnt;
inline void dfs2(int x,int Top)
{
	top[x]=Top;id[x]=++id_cnt;rid[id_cnt]=x;
	if(hson[x]) dfs2(hson[x],Top);
	for(int i=head[x];i;i=nxt[i])
	{
		int y=ver[i];if(y==fa[x]||y==hson[x]) continue;
		dfs2(y,y);
	}
}
struct segment_tree
{
	#define lson(x) (x<<1)
	#define rson(x) (x<<1|1)
	long long sumv[maxn<<2],addv[maxn<<2];
	inline void pushup(int p){sumv[p]=sumv[lson(p)]+sumv[rson(p)];}
	inline void build(int p,int l,int r)
	{
		if(l==r) return (void)(sumv[p]=a[rid[l]]);
		int mid=(l+r)>>1;
		build(lson(p),l,mid);build(rson(p),mid+1,r);
		pushup(p);
	}
	inline void setadd(int p,int l,int r,int Add)
	{
		addv[p]+=Add;
		sumv[p]+=Add*(r-l+1);
	}
	inline void pushdown(int p,int l,int r)
	{
		if(addv[p]==0) return;int mid=(l+r)>>1;
		setadd(lson(p),l,mid,addv[p]);
		setadd(rson(p),mid+1,r,addv[p]);
		addv[p]=0;
	}
	inline void add(int p,int l,int r,int ql,int qr,int Add)
	{
		if(ql<=l&&qr>=r) return (void)setadd(p,l,r,Add);
		int mid=(l+r)>>1;pushdown(p,l,r);
		if(ql<=mid) add(lson(p),l,mid,ql,qr,Add);
		if(qr>mid) add(rson(p),mid+1,r,ql,qr,Add);
		pushup(p);
	}
	inline int Qsum(int p,int l,int r,int ql,int qr)
	{
		if(ql<=l&&qr>=r) return sumv[p];
		int mid=(l+r)>>1,res=0;pushdown(p,l,r);
		if(ql<=mid) res+=Qsum(lson(p),l,mid,ql,qr);
		if(qr>mid) res+=Qsum(rson(p),mid+1,r,ql,qr);
		return res;
	}
}seg;
inline void init()
{
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;i++) scanf("%lld",a+i);
	for(int i=1,a,b;i<n;i++) scanf("%lld%lld",&a,&b),addedge(a,b);
	dfs1(1,0);dfs2(1,1);
	seg.build(1,1,n);root=1;
	for(int j=1;j<=20;j++) for(int i=1;i<=n;i++) Fa[i][j]=Fa[Fa[i][j-1]][j-1];
}
inline int lca(int a,int b)
{
	while(top[a]!=top[b])
	{
		if(dep[top[a]]<dep[top[b]]) swap(a,b);
		a=fa[top[a]];
	}
	if(dep[a]>dep[b]) swap(a,b);
	return a;
}
inline int getlca(int a,int b)
{
	if(a==b) return a;
	int A=lca(a,b),B=lca(a,root),C=lca(b,root);
	int Mindep=0,ans=-1;
	if(dep[A]>Mindep) Mindep=dep[A],ans=A;
	if(dep[B]>Mindep) Mindep=dep[B],ans=B;
	if(dep[C]>Mindep) Mindep=dep[C],ans=C;
	return ans;
}
inline int RUN(int from,int to)
{
	int Dep=dep[from]-dep[to]-1;
	for(int i=20;i>=0;i--) if(Dep&(1<<i)) from=Fa[from][i];
	return from;
}
inline void add_subtree(int x,int Add)
{
	if(x==root) return (void)seg.add(1,1,n,1,n,Add);
	int L=id[x],R=id[x]+size[x]-1;
	if(id[root]<L||id[root]>R) return (void)seg.add(1,1,n,L,R,Add);
	int Sub=RUN(root,x);
	L=id[Sub];R=id[Sub]+size[Sub]-1;
	if(L>1) seg.add(1,1,n,1,L-1,Add);if(R<n) seg.add(1,1,n,R+1,n,Add);
}
inline int Qsubtree(int x)
{
	if(x==root) return seg.Qsum(1,1,n,1,n);
	int L=id[x],R=id[x]+size[x]-1;
	if(id[root]<L||id[root]>R) return seg.Qsum(1,1,n,L,R);
	int Sub=RUN(root,x);
	L=id[Sub];R=id[Sub]+size[Sub]-1;int ans=0;
	if(L>1) ans+=seg.Qsum(1,1,n,1,L-1);if(R<n) ans+=seg.Qsum(1,1,n,R+1,n);
	return ans;
}
signed main()
{
	init();int a,b,c,d;//for(int i=1;i<=n;i++) cout<<fa[i]<<' ';putchar('\n');
//	while(cin>>a>>b) cout<<RUN(a,b)<<endl;
	while(m--)
	{
		scanf("%lld",&a);
		if(a==1) scanf("%lld",&root);
		if(a==2) scanf("%lld%lld%lld",&b,&c,&d),add_subtree(getlca(b,c),d);
		if(a==3) scanf("%lld",&b),printf("%lld\n",Qsubtree(b));
	}
}
/*
6 1000
1 4 2 8 5 7
1 2
3 1
4 3
4 5
3 6
3 1
2 4 6 3
3 4
1 6
2 2 4 -5
1 4
3 3
3 2
3 3
3 1
3 6
*/


#include<bits/stdc++.h>
using namespace std;
#define maxn 100001
long long a[maxn];int n,m;int root;
int head[maxn],ver[maxn<<1],nxt[maxn<<1],tot;
inline void addedge(int a,int b)
{
	nxt[++tot]=head[a];ver[tot]=b;head[a]=tot;
	nxt[++tot]=head[b];ver[tot]=a;head[b]=tot;
}
int size[maxn],hson[maxn],fa[maxn],dep[maxn];
int Fa[maxn][23];
inline void dfs1(int x,int fat)
{
	size[x]=1;fa[x]=fat;dep[x]=dep[fat]+1;Fa[x][0]=fat;
	int maxsize=0;
	for(int i=head[x];i;i=nxt[i])
	{
		int y=ver[i];if(y==fat) continue;
		dfs1(y,x);size[x]+=size[y];
		if(size[y]>maxsize) maxsize=size[y],hson[x]=y;
	}
}
int top[maxn],id[maxn],rid[maxn],id_cnt;
inline void dfs2(int x,int Top)
{
	top[x]=Top;id[x]=++id_cnt;rid[id_cnt]=x;
	if(hson[x]) dfs2(hson[x],Top);
	for(int i=head[x];i;i=nxt[i])
	{
		int y=ver[i];if(y==fa[x]||y==hson[x]) continue;
		dfs2(y,y);
	}
}
struct segment_tree
{
	#define lson(x) (x<<1)
	#define rson(x) (x<<1|1)
	long long sumv[maxn<<2],addv[maxn<<2];
	inline void pushup(int p){sumv[p]=sumv[lson(p)]+sumv[rson(p)];}
	inline void build(int p,int l,int r)
	{
		if(l==r) return (void)(sumv[p]=a[rid[l]]);
		int mid=(l+r)>>1;
		build(lson(p),l,mid);build(rson(p),mid+1,r);
		pushup(p);
	}
	inline void setadd(int p,int l,int r,int Add)
	{
		addv[p]+=Add;
		sumv[p]+=Add*(r-l+1);
	}
	inline void pushdown(int p,int l,int r)
	{
		if(addv[p]==0) return;int mid=(l+r)>>1;
		setadd(lson(p),l,mid,addv[p]);
		setadd(rson(p),mid+1,r,addv[p]);
		addv[p]=0;
	}
	inline void add(int p,int l,int r,int ql,int qr,int Add)
	{
		if(ql<=l&&qr>=r) return (void)setadd(p,l,r,Add);
		int mid=(l+r)>>1;pushdown(p,l,r);
		if(ql<=mid) add(lson(p),l,mid,ql,qr,Add);
		if(qr>mid) add(rson(p),mid+1,r,ql,qr,Add);
		pushup(p);
	}
	inline int Qsum(int p,int l,int r,int ql,int qr)
	{
		if(ql<=l&&qr>=r) return sumv[p];
		int mid=(l+r)>>1,res=0;pushdown(p,l,r);
		if(ql<=mid) res+=Qsum(lson(p),l,mid,ql,qr);
		if(qr>mid) res+=Qsum(rson(p),mid+1,r,ql,qr);
		return res;
	}
}seg;
inline void init()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%lld",a+i);
	for(int i=1,a,b;i<n;i++) scanf("%d%d",&a,&b),addedge(a,b);
	dfs1(1,0);dfs2(1,1);
	seg.build(1,1,n);root=1;
	for(int j=1;j<=20;j++) for(int i=1;i<=n;i++) Fa[i][j]=Fa[Fa[i][j-1]][j-1];
}
inline int lca(int a,int b)
{
	while(top[a]!=top[b])
	{
		if(dep[top[a]]<dep[top[b]]) swap(a,b);
		a=fa[top[a]];
	}
	if(dep[a]>dep[b]) swap(a,b);
	return a;
}
inline int getlca(int a,int b)
{
	if(a==b) return a;
	int A=lca(a,b),B=lca(a,root),C=lca(b,root);
	int Mindep=0,ans=-1;
	if(dep[A]>Mindep) Mindep=dep[A],ans=A;
	if(dep[B]>Mindep) Mindep=dep[B],ans=B;
	if(dep[C]>Mindep) Mindep=dep[C],ans=C;
	return ans;
}
inline int RUN(int from,int to)
{
	int Dep=dep[from]-dep[to]-1;
	for(int i=20;i>=0;i--) if(Dep&(1<<i)) from=Fa[from][i];
	return from;
}
inline void add_subtree(int x,int Add)
{
	if(x==root) return (void)seg.add(1,1,n,1,n,Add);
	int L=id[x],R=id[x]+size[x]-1;
	if(id[root]<L||id[root]>R) return (void)seg.add(1,1,n,L,R,Add);
	int Sub=RUN(root,x);
	L=id[Sub];R=id[Sub]+size[Sub]-1;
	if(L>1) seg.add(1,1,n,1,L-1,Add);if(R<n) seg.add(1,1,n,R+1,n,Add);
}
inline int Qsubtree(int x)
{
	if(x==root) return seg.Qsum(1,1,n,1,n);
	int L=id[x],R=id[x]+size[x]-1;
	if(id[root]<L||id[root]>R) return seg.Qsum(1,1,n,L,R);
	int Sub=RUN(root,x);
	L=id[Sub];R=id[Sub]+size[Sub]-1;int ans=0;
	if(L>1) ans+=seg.Qsum(1,1,n,1,L-1);if(R<n) ans+=seg.Qsum(1,1,n,R+1,n);
	return ans;
}
int main()
{
	init();int a,b,c,d;//for(int i=1;i<=n;i++) cout<<fa[i]<<' ';putchar('\n');
//	while(cin>>a>>b) cout<<RUN(a,b)<<endl;
	while(m--)
	{
		scanf("%d",&a);
		if(a==1) scanf("%d",&root);
		if(a==2) scanf("%d%d%d",&b,&c,&d),add_subtree(getlca(b,c),d);
		if(a==3) scanf("%d",&b),printf("%d\n",Qsubtree(b));
	}
}
/*
6 1000
1 4 2 8 5 7
1 2
3 1
4 3
4 5
3 6
3 1
2 4 6 3
3 4
1 6
2 2 4 -5
1 4
3 3
3 2
3 3
3 1
3 6
*//4f53dsa4d56sa4f


#include<bits/stdc++.h>
using namespace std;
#define maxn 100001
#define int long long
long long a[maxn];int n,m;int root;
int head[maxn],ver[maxn<<1],nxt[maxn<<1],tot;
inline void addedge(int a,int b)
{
	nxt[++tot]=head[a];ver[tot]=b;head[a]=tot;
	nxt[++tot]=head[b];ver[tot]=a;head[b]=tot;
}
int size[maxn],hson[maxn],fa[maxn],dep[maxn];
int Fa[maxn][23];
inline void dfs1(int x,int fat)
{
	size[x]=1;fa[x]=fat;dep[x]=dep[fat]+1;Fa[x][0]=fat;
	int maxsize=0;
	for(int i=head[x];i;i=nxt[i])
	{
		int y=ver[i];if(y==fat) continue;
		dfs1(y,x);size[x]+=size[y];
		if(size[y]>maxsize) maxsize=size[y],hson[x]=y;
	}
}
int top[maxn],id[maxn],rid[maxn],id_cnt;
inline void dfs2(int x,int Top)
{
	top[x]=Top;id[x]=++id_cnt;rid[id_cnt]=x;
	if(hson[x]) dfs2(hson[x],Top);
	for(int i=head[x];i;i=nxt[i])
	{
		int y=ver[i];if(y==fa[x]||y==hson[x]) continue;
		dfs2(y,y);
	}
}
struct segment_tree
{
	#define lson(x) (x<<1)
	#define rson(x) (x<<1|1)
	long long sumv[maxn<<2],addv[maxn<<2];
	inline void pushup(int p){sumv[p]=sumv[lson(p)]+sumv[rson(p)];}
	inline void build(int p,int l,int r)
	{
		if(l==r) return (void)(sumv[p]=a[rid[l]]);
		int mid=(l+r)>>1;
		build(lson(p),l,mid);build(rson(p),mid+1,r);
		pushup(p);
	}
	inline void setadd(int p,int l,int r,int Add)
	{
		addv[p]+=Add;
		sumv[p]+=Add*(r-l+1);
	}
	inline void pushdown(int p,int l,int r)
	{
		if(addv[p]==0) return;int mid=(l+r)>>1;
		setadd(lson(p),l,mid,addv[p]);
		setadd(rson(p),mid+1,r,addv[p]);
		addv[p]=0;
	}
	inline void add(int p,int l,int r,int ql,int qr,int Add)
	{
		if(ql<=l&&qr>=r) return (void)setadd(p,l,r,Add);
		int mid=(l+r)>>1;pushdown(p,l,r);
		if(ql<=mid) add(lson(p),l,mid,ql,qr,Add);
		if(qr>mid) add(rson(p),mid+1,r,ql,qr,Add);
		pushup(p);
	}
	inline int Qsum(int p,int l,int r,int ql,int qr)
	{
		if(ql<=l&&qr>=r) return sumv[p];
		int mid=(l+r)>>1,res=0;pushdown(p,l,r);
		if(ql<=mid) res+=Qsum(lson(p),l,mid,ql,qr);
		if(qr>mid) res+=Qsum(rson(p),mid+1,r,ql,qr);
		return res;
	}
}seg;
inline void init()
{
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;i++) scanf("%lld",a+i);
	for(int i=1,a,b;i<n;i++) scanf("%lld%lld",&a,&b),addedge(a,b);
	dfs1(1,0);dfs2(1,1);
	seg.build(1,1,n);root=1;
	for(int j=1;j<=20;j++) for(int i=1;i<=n;i++) Fa[i][j]=Fa[Fa[i][j-1]][j-1];
}
inline int lca(int a,int b)
{
	while(top[a]!=top[b])
	{
		if(dep[top[a]]<dep[top[b]]) swap(a,b);
		a=fa[top[a]];
	}
	if(dep[a]>dep[b]) swap(a,b);
	return a;
}
inline int getlca(int a,int b)
{
	if(a==b) return a;
	int A=lca(a,b),B=lca(a,root),C=lca(b,root);
	int Mindep=0,ans=-1;
	if(dep[A]>Mindep) Mindep=dep[A],ans=A;
	if(dep[B]>Mindep) Mindep=dep[B],ans=B;
	if(dep[C]>Mindep) Mindep=dep[C],ans=C;
	return ans;
}
inline int RUN(int from,int to)
{
	int Dep=dep[from]-dep[to]-1;
	for(int i=20;i>=0;i--) if(Dep&(1<<i)) from=Fa[from][i];
	return from;
}
inline void add_subtree(int x,int Add)
{
	if(x==root) return (void)seg.add(1,1,n,1,n,Add);
	int L=id[x],R=id[x]+size[x]-1;
	if(id[root]<L||id[root]>R) return (void)seg.add(1,1,n,L,R,Add);
	int Sub=RUN(root,x);
	L=id[Sub];R=id[Sub]+size[Sub]-1;
	if(L>1) seg.add(1,1,n,1,L-1,Add);if(R<n) seg.add(1,1,n,R+1,n,Add);
}
inline int Qsubtree(int x)
{
	if(x==root) return seg.Qsum(1,1,n,1,n);
	int L=id[x],R=id[x]+size[x]-1;
	if(id[root]<L||id[root]>R) return seg.Qsum(1,1,n,L,R);
	int Sub=RUN(root,x);
	L=id[Sub];R=id[Sub]+size[Sub]-1;int ans=0;
	if(L>1) ans+=seg.Qsum(1,1,n,1,L-1);if(R<n) ans+=seg.Qsum(1,1,n,R+1,n);
	return ans;
}
signed main()
{
	init();int a,b,c,d;
	while(m--)
	{
		scanf("%lld",&a);
		if(a==1) scanf("%lld",&root);
		if(a==2) scanf("%lld%lld%lld",&b,&c,&d),add_subtree(getlca(b,c),d);
		if(a==3) scanf("%lld",&b),printf("%lld\n",Qsubtree(b));
	}
}


#include<bits/stdc++.h>
using namespace std;
#define maxn 100001
long long a[maxn];int n,m;int root;
int head[maxn],ver[maxn<<1],nxt[maxn<<1],tot;
inline void addedge(int a,int b)
{
	nxt[++tot]=head[a];ver[tot]=b;head[a]=tot;
	nxt[++tot]=head[b];ver[tot]=a;head[b]=tot;
}
int size[maxn],hson[maxn],fa[maxn],dep[maxn];
int Fa[maxn][23];
inline void dfs1(int x,int fat)
{
	size[x]=1;fa[x]=fat;dep[x]=dep[fat]+1;Fa[x][0]=fat;
	int maxsize=0;
	for(int i=head[x];i;i=nxt[i])
	{
		int y=ver[i];if(y==fat) continue;
		dfs1(y,x);size[x]+=size[y];
		if(size[y]>maxsize) maxsize=size[y],hson[x]=y;
	}
}
int top[maxn],id[maxn],rid[maxn],id_cnt;
inline void dfs2(int x,int Top)
{
	top[x]=Top;id[x]=++id_cnt;rid[id_cnt]=x;
	if(hson[x]) dfs2(hson[x],Top);
	for(int i=head[x];i;i=nxt[i])
	{
		int y=ver[i];if(y==fa[x]||y==hson[x]) continue;
		dfs2(y,y);
	}
}
struct segment_tree
{
	#define lson(x) (x<<1)
	#define rson(x) (x<<1|1)
	long long sumv[maxn<<2],addv[maxn<<2];
	inline void pushup(int p){sumv[p]=sumv[lson(p)]+sumv[rson(p)];}
	inline void build(int p,int l,int r)
	{
		if(l==r) return (void)(sumv[p]=a[rid[l]]);
		int mid=(l+r)>>1;
		build(lson(p),l,mid);build(rson(p),mid+1,r);
		pushup(p);
	}
	inline void setadd(int p,int l,int r,int Add)
	{
		addv[p]+=Add;
		sumv[p]+=Add*(r-l+1);
	}
	inline void pushdown(int p,int l,int r)
	{
		if(addv[p]==0) return;int mid=(l+r)>>1;
		setadd(lson(p),l,mid,addv[p]);
		setadd(rson(p),mid+1,r,addv[p]);
		addv[p]=0;
	}
	inline void add(int p,int l,int r,int ql,int qr,int Add)
	{
		if(ql<=l&&qr>=r) return (void)setadd(p,l,r,Add);
		int mid=(l+r)>>1;pushdown(p,l,r);
		if(ql<=mid) add(lson(p),l,mid,ql,qr,Add);
		if(qr>mid) add(rson(p),mid+1,r,ql,qr,Add);
		pushup(p);
	}
	inline int Qsum(int p,int l,int r,int ql,int qr)
	{
		if(ql<=l&&qr>=r) return sumv[p];
		int mid=(l+r)>>1,res=0;pushdown(p,l,r);
		if(ql<=mid) res+=Qsum(lson(p),l,mid,ql,qr);
		if(qr>mid) res+=Qsum(rson(p),mid+1,r,ql,qr);
		return res;
	}
}seg;
inline void init()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%lld",a+i);
	for(int i=1,a,b;i<n;i++) scanf("%d%d",&a,&b),addedge(a,b);
	dfs1(1,0);dfs2(1,1);
	seg.build(1,1,n);root=1;
	for(int j=1;j<=20;j++) for(int i=1;i<=n;i++) Fa[i][j]=Fa[Fa[i][j-1]][j-1];
}
inline int lca(int a,int b)
{
	while(top[a]!=top[b])
	{
		if(dep[top[a]]<dep[top[b]]) swap(a,b);
		a=fa[top[a]];
	}
	if(dep[a]>dep[b]) swap(a,b);
	return a;
}
inline int getlca(int a,int b)
{
	if(a==b) return a;
	int A=lca(a,b),B=lca(a,root),C=lca(b,root);
	int Mindep=0,ans=-1;
	if(dep[A]>Mindep) Mindep=dep[A],ans=A;
	if(dep[B]>Mindep) Mindep=dep[B],ans=B;
	if(dep[C]>Mindep) Mindep=dep[C],ans=C;
	return ans;
}
inline int RUN(int from,int to)
{
	int Dep=dep[from]-dep[to]-1;
	for(int i=20;i>=0;i--) if(Dep&(1<<i)) from=Fa[from][i];
	return from;
}
inline void add_subtree(int x,int Add)
{
	if(x==root) return (void)seg.add(1,1,n,1,n,Add);
	int L=id[x],R=id[x]+size[x]-1;
	if(id[root]<L||id[root]>R) return (void)seg.add(1,1,n,L,R,Add);
	int Sub=RUN(root,x);
	L=id[Sub];R=id[Sub]+size[Sub]-1;
	if(L>1) seg.add(1,1,n,1,L-1,Add);if(R<n) seg.add(1,1,n,R+1,n,Add);
}
inline int Qsubtree(int x)
{
	if(x==root) return seg.Qsum(1,1,n,1,n);
	int L=id[x],R=id[x]+size[x]-1;
	if(id[root]<L||id[root]>R) return seg.Qsum(1,1,n,L,R);
	int Sub=RUN(root,x);
	L=id[Sub];R=id[Sub]+size[Sub]-1;int ans=0;
	if(L>1) ans+=seg.Qsum(1,1,n,1,L-1);if(R<n) ans+=seg.Qsum(1,1,n,R+1,n);
	return ans;
}
int main()
{
	init();int a,b,c,d;//for(int i=1;i<=n;i++) cout<<fa[i]<<' ';putchar('\n');
//	while(cin>>a>>b) cout<<RUN(a,b)<<endl;
	while(m--)
	{
		scanf("%d",&a);
		if(a==1) scanf("%d",&root);
		if(a==2) scanf("%d%d%d",&b,&c,&d),add_subtree(getlca(b,c),d);
		if(a==3) scanf("%d",&b),printf("%d\n",Qsubtree(b));
	}
}
/*
6 1000
1 4 2 8 5 7
1 2
3 1
4 3
4 5
3 6
3 1
2 4 6 3
3 4
1 6
2 2 4 -5
1 4
3 3
3 2
3 3
3 1
3 6
*/


#include <cstdio>
#define ll long long
#define ls id<<1
#define rs id<<1|1
const int N=100010;
int head[N],to[N<<1],Next[N<<1],cnt;
void add(int u,int v)
{
    to[++cnt]=v;Next[cnt]=head[u];head[u]=cnt;
}
int f[N][20],dfn[N],dep[N],siz[N],ha[N],dfs_clock,root;
void dfs(int now)
{
    dfn[now]=++dfs_clock;
    ha[dfs_clock]=now;
    siz[now]++;
    for(int i=head[now];i;i=Next[i])
    {
        int v=to[i];
        if(f[now][0]!=v)
        {
            dep[v]=dep[now]+1;
            f[v][0]=now;
            dfs(v);
            siz[now]+=siz[v];
        }
    }
}
ll sum[N<<2],lazy[N<<2],dat[N];
int n,q;
void updata(int id)
{
    sum[id]=sum[ls]+sum[rs];
}
void push_down(int id,ll L,ll R)
{
    if(!lazy[id]) return;
    if(L!=R)
    {
        ll mid=L+R>>1;
        sum[ls]+=(mid+1-L)*lazy[id];
        sum[rs]+=(R-mid)*lazy[id];
        lazy[ls]+=lazy[id];
        lazy[rs]+=lazy[id];
    }
    lazy[id]=0;
}
void build(int id,int l,int r)
{
    if(l==r)
    {
        sum[id]=dat[ha[l]];
        return;
    }
    int mid=l+r>>1;
    build(ls,l,mid);
    build(rs,mid+1,r);
    updata(id);
}
void change(int id,ll l,ll r,ll L,ll R,ll delta)
{
    push_down(id,L,R);
    if(l==L&&r==R)
    {
        sum[id]+=(R+1-L)*delta;
        lazy[id]+=delta;
        return;
    }
    ll mid=L+R>>1;
    if(r<=mid) change(ls,l,r,L,mid,delta);
    else if(l>mid) change(rs,l,r,mid+1,R,delta);
    else change(ls,l,mid,L,mid,delta),change(rs,mid+1,r,mid+1,R,delta);
    updata(id);
}
ll query(int id,ll l,ll r,ll L,ll R)
{
    push_down(id,L,R);
    if(l==L&&r==R) return sum[id];
    ll mid=L+R>>1;
    if(r<=mid) return query(ls,l,r,L,mid);
    else if(l>mid) return query(rs,l,r,mid+1,R);
    else return query(ls,l,mid,L,mid)+query(rs,mid+1,r,mid+1,R);
}
void init()
{
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++) scanf("%lld",dat+i);
    for(int u,v,i=1;i<n;i++)
    {
        scanf("%d%d",&u,&v);
        add(u,v),add(v,u);
    }
    dep[1]=1;
    dfs(root=1);
    for(int j=1;j<=18;j++)
        for(int i=1;i<=n;i++)
            f[i][j]=f[f[i][j-1]][j-1];
    build(1,1,n);
}
void Swap(int &x,int &y)
{
    int tmp=x;
    x=y;
    y=tmp;
}
int LCA0(int x,int y)//原树的LCA
{
    if(dep[x]<dep[y]) Swap(x,y);
    for(int i=18;~i;i--)
        if(dep[f[x][i]]>=dep[y])
            x=f[x][i];
    if(x==y) return x;
    for(int i=18;~i;i--)
        if(f[x][i]!=f[y][i])
            x=f[x][i],y=f[y][i];
    return f[x][0];
}
int LCA(int x,int y)//换根后的LCA
{
    int z1=LCA0(x,root),z2=LCA0(y,root);
    if(z1==z2) return LCA0(x,y);
    else return dep[z1]>dep[z2]?z1:z2;
}
bool in(int x)//询问x是否在以root为根的子树里
{
    if(dfn[x]>=dfn[root]&&dfn[x]<=dfn[root]+siz[root]-1) return true;
    return false;
}
int querys(int x)//询问根到x位置上x的那个儿子
{
    int y=root;
    for(int i=18;~i;i--)
        if(dep[f[y][i]]>dep[x])
            y=f[y][i];
    return y;
}
void modify(int x,ll delta)//给以x为根的子树加上delta
{
    if(in(x))
    {
        if(x!=root) change(1,dfn[x],dfn[x]+siz[x]-1,1,n,delta);
        else change(1,1,n,1,n,delta);
        return;
    }
    int son=querys(x);
    if(f[son][0]==x)
    {
        change(1,1,n,1,n,delta);
        change(1,dfn[son],dfn[son]+siz[son]-1,1,n,-delta);
    }
    else
        change(1,dfn[x],dfn[x]+siz[x]-1,1,n,delta);
}
ll ask(int x)//询问新根下子树权值和
{
    if(in(x))
        return query(1,dfn[x],dfn[x]+siz[x]-1,1,n);
    int son=querys(x);
    ll ans=0;
    if(f[son][0]==x)
    {
        ans+=query(1,1,n,1,n);
        ans-=query(1,dfn[son],dfn[son]+siz[son]-1,1,n);
    }
    else
        ans=query(1,dfn[x],dfn[x]+siz[x]-1,1,n);
    return ans;
}
void work()
{
    ll x;
    for(int opt,u,v,i=1;i<=q;i++)
    {
        scanf("%d",&opt);
        if(opt==1)
        {
            scanf("%d",&u);
            root=u;
        }
        else if(opt==2)
        {
            scanf("%d%d%lld",&u,&v,&x);
            modify(LCA(u,v),x);
        }
        else
        {
            scanf("%d",&u);
            printf("%lld\n",ask(u));
        }
    }
}
int main()
{
    init();
    work();
    return 0;
}


#include <cstdio>
#define ll long long
#define ls id<<1
#define rs id<<1|1
const int N=100010;
int head[N],to[N<<1],Next[N<<1],cnt;
void add(int u,int v)
{
    to[++cnt]=v;Next[cnt]=head[u];head[u]=cnt;
}
int f[N][20],dfn[N],dep[N],siz[N],ha[N],dfs_clock,root;
void dfs(int now)
{
    dfn[now]=++dfs_clock;
    ha[dfs_clock]=now;
    siz[now]++;
    for(int i=head[now];i;i=Next[i])
    {
        int v=to[i];
        if(f[now][0]!=v)
        {
            dep[v]=dep[now]+1;
            f[v][0]=now;
            dfs(v);
            siz[now]+=siz[v];
        }
    }
}
ll sum[N<<2],lazy[N<<2],dat[N];
int n,q;
void updata(int id)
{
    sum[id]=sum[ls]+sum[rs];
}
void push_down(int id,ll L,ll R)
{
    if(!lazy[id]) return;
    if(L!=R)
    {
        ll mid=L+R>>1;
        sum[ls]+=(mid+1-L)*lazy[id];
        sum[rs]+=(R-mid)*lazy[id];
        lazy[ls]+=lazy[id];
        lazy[rs]+=lazy[id];
    }
    lazy[id]=0;
}
void build(int id,int l,int r)
{
    if(l==r)
    {
        sum[id]=dat[ha[l]];
        return;
    }
    int mid=l+r>>1;
    build(ls,l,mid);
    build(rs,mid+1,r);
    updata(id);
}
void change(int id,ll l,ll r,ll L,ll R,ll delta)
{
    push_down(id,L,R);
    if(l==L&&r==R)
    {
        sum[id]+=(R+1-L)*delta;
        lazy[id]+=delta;
        return;
    }
    ll mid=L+R>>1;
    if(r<=mid) change(ls,l,r,L,mid,delta);
    else if(l>mid) change(rs,l,r,mid+1,R,delta);
    else change(ls,l,mid,L,mid,delta),change(rs,mid+1,r,mid+1,R,delta);
    updata(id);
}
ll query(int id,ll l,ll r,ll L,ll R)
{
    push_down(id,L,R);
    if(l==L&&r==R) return sum[id];
    ll mid=L+R>>1;
    if(r<=mid) return query(ls,l,r,L,mid);
    else if(l>mid) return query(rs,l,r,mid+1,R);
    else return query(ls,l,mid,L,mid)+query(rs,mid+1,r,mid+1,R);
}
void init()
{
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++) scanf("%lld",dat+i);
    for(int u,v,i=1;i<n;i++)
    {
        scanf("%d%d",&u,&v);
        add(u,v),add(v,u);
    }
    dep[1]=1;
    dfs(root=1);
    for(int j=1;j<=18;j++)
        for(int i=1;i<=n;i++)
            f[i][j]=f[f[i][j-1]][j-1];
    build(1,1,n);
}
void Swap(int &x,int &y)
{
    int tmp=x;
    x=y;
    y=tmp;
}
int LCA0(int x,int y)//原树的LCA
{
    if(dep[x]<dep[y]) Swap(x,y);
    for(int i=18;~i;i--)
        if(dep[f[x][i]]>=dep[y])
            x=f[x][i];
    if(x==y) return x;
    for(int i=18;~i;i--)
        if(f[x][i]!=f[y][i])
            x=f[x][i],y=f[y][i];
    return f[x][0];
}
int LCA(int x,int y)//换根后的LCA
{
    int z1=LCA0(x,root),z2=LCA0(y,root);
    if(z1==z2) return LCA0(x,y);
    else return dep[z1]>dep[z2]?z1:z2;
}
bool in(int x)//询问x是否在以root为根的子树里
{
    if(dfn[x]>=dfn[root]&&dfn[x]<=dfn[root]+siz[root]-1) return true;
    return false;
}
int querys(int x)//询问根到x位置上x的那个儿子
{
    int y=root;
    for(int i=18;~i;i--)
        if(dep[f[y][i]]>dep[x])
            y=f[y][i];
    return y;
}
void modify(int x,ll delta)//给以x为根的子树加上delta
{
    if(in(x))
    {
        if(x!=root) change(1,dfn[x],dfn[x]+siz[x]-1,1,n,delta);
        else change(1,1,n,1,n,delta);
        return;
    }
    int son=querys(x);
    if(f[son][0]==x)
    {
        change(1,1,n,1,n,delta);
        change(1,dfn[son],dfn[son]+siz[son]-1,1,n,-delta);
    }
    else
        change(1,dfn[x],dfn[x]+siz[x]-1,1,n,delta);
}
ll ask(int x)//询问新根下子树权值和
{
    if(in(x))
    {
        if(x!=root) return query(1,dfn[x],dfn[x]+siz[x]-1,1,n);
        return query(1,1,n,1,n);
    }
    int son=querys(x);
    ll ans=0;
    if(f[son][0]==x)
    {
        ans+=query(1,1,n,1,n);
        ans-=query(1,dfn[son],dfn[son]+siz[son]-1,1,n);
    }
    else
        ans=query(1,dfn[x],dfn[x]+siz[x]-1,1,n);
    return ans;
}
void work()
{
    ll x,y;
    for(int opt,u,v,i=1;i<=q;i++)
    {
        scanf("%d",&opt);
        if(opt==1)
        {
            scanf("%d",&u);
            root=u;
        }
        else if(opt==2)
        {
            scanf("%d%d%lld",&u,&v,&x);
            modify(LCA(u,v),x);
        }
        else
        {
            scanf("%d",&u);
            printf("%lld\n",ask(u));
        }
    }
}
int main()
{
    init();
    work();
    return 0;
}


#include <cstdio>
#define ll long long
#define ls id<<1
#define rs id<<1|1
const int N=100010;
int head[N],to[N<<1],Next[N<<1],cnt;
void add(int u,int v)
{
    to[++cnt]=v;Next[cnt]=head[u];head[u]=cnt;
}
int f[N][20],dfn[N],dep[N],siz[N],ha[N],dfs_clock,root;
void dfs(int now)
{
    dfn[now]=++dfs_clock;
    ha[dfs_clock]=now;
    siz[now]++;
    for(int i=head[now];i;i=Next[i])
    {
        int v=to[i];
        if(f[now][0]!=v)
        {
            dep[v]=dep[now]+1;
            f[v][0]=now;
            dfs(v);
            siz[now]+=siz[v];
        }
    }
}
ll sum[N<<2],lazy[N<<2],dat[N];
int n,q;
void updata(int id)
{
    sum[id]=sum[ls]+sum[rs];
}
void push_down(int id,ll L,ll R)
{
    if(!lazy[id]) return;
    if(L!=R)
    {
        ll mid=L+R>>1;
        sum[ls]+=(mid+1-L)*lazy[id];
        sum[rs]+=(R-mid)*lazy[id];
        lazy[ls]+=lazy[id];
        lazy[rs]+=lazy[id];
    }
    lazy[id]=0;
}
void build(int id,int l,int r)
{
    if(l==r)
    {
        sum[id]=dat[ha[l]];
        return;
    }
    int mid=l+r>>1;
    build(ls,l,mid);
    build(rs,mid+1,r);
    updata(id);
}
void change(int id,ll l,ll r,ll L,ll R,ll delta)
{
    push_down(id,L,R);
    if(l==L&&r==R)
    {
        sum[id]+=(R+1-L)*delta;
        lazy[id]+=delta;
        return;
    }
    ll mid=L+R>>1;
    if(r<=mid) change(ls,l,r,L,mid,delta);
    else if(l>mid) change(rs,l,r,mid+1,R,delta);
    else change(ls,l,mid,L,mid,delta),change(rs,mid+1,r,mid+1,R,delta);
    updata(id);
}
ll query(int id,ll l,ll r,ll L,ll R)
{
    push_down(id,L,R);
    if(l==L&&r==R) return sum[id];
    ll mid=L+R>>1;
    if(r<=mid) return query(ls,l,r,L,mid);
    else if(l>mid) return query(rs,l,r,mid+1,R);
    else return query(ls,l,mid,L,mid)+query(rs,mid+1,r,mid+1,R);
}
void init()
{
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++) scanf("%lld",dat+i);
    for(int u,v,i=1;i<n;i++)
    {
        scanf("%d%d",&u,&v);
        add(u,v),add(v,u);
    }
    dep[1]=1;
    dfs(root=1);
    for(int j=1;j<=18;j++)
        for(int i=1;i<=n;i++)
            f[i][j]=f[f[i][j-1]][j-1];
    build(1,1,n);
}
void Swap(int &x,int &y)
{
    int tmp=x;
    x=y;
    y=tmp;
}
int LCA0(int x,int y)//原树的LCA
{
    if(dep[x]<dep[y]) Swap(x,y);
    for(int i=18;~i;i--)
        if(dep[f[x][i]]>=dep[y])
            x=f[x][i];
    if(x==y) return x;
    for(int i=18;~i;i--)
        if(f[x][i]!=f[y][i])
            x=f[x][i],y=f[y][i];
    return f[x][0];
}
int LCA(int x,int y)//换根后的LCA
{
    int z1=LCA0(x,root),z2=LCA0(y,root);
    if(z1==z2) return LCA0(x,y);
    else return dep[z1]>dep[z2]?z1:z2;
}
bool in(int x)//询问x是否在以root为根的子树里
{
    if(dfn[x]>=dfn[root]&&dfn[x]<=dfn[root]+siz[root]-1) return true;
    return false;
}
int querys(int x)//询问根到x位置上x的那个儿子
{
    int y=root;
    for(int i=18;~i;i--)
        if(dep[f[y][i]]>dep[x])
            y=f[y][i];
    return y;
}
void modify(int x,ll delta)//给以x为根的子树加上delta
{
    if(in(x))
    {
        if(x!=root) change(1,dfn[x],dfn[x]+siz[x]-1,1,n,delta);
        else change(1,1,n,1,n,delta);
        return;
    }
    int son=querys(x);
    if(f[son][0]==x)
    {
        change(1,1,n,1,n,delta);
        change(1,dfn[son],dfn[son]+siz[son]-1,1,n,-delta);
    }
    else
        change(1,dfn[x],dfn[x]+siz[x]-1,1,n,delta);
}
ll ask(int x)//询问新根下子树权值和
{
    if(in(x))
    {
        if(x!=root) return query(1,dfn[x],dfn[x]+siz[x]-1,1,n);
        return query(1,1,n,1,n);
    }
    int son=querys(x);
    ll ans=0;
    if(f[son][0]==x)
    {
        ans+=query(1,1,n,1,n);
        ans-=query(1,dfn[son],dfn[son]+siz[son]-1,1,n);
    }
    else
        ans=query(1,dfn[x],dfn[x]+siz[x]-1,1,n);
    return ans;
}
void work()
{
    ll x;
    for(int opt,u,v,i=1;i<=q;i++)
    {
        scanf("%d",&opt);
        if(opt==1)
        {
            scanf("%d",&u);
            root=u;
        }
        else if(opt==2)
        {
            scanf("%d%d%lld",&u,&v,&x);
            modify(LCA(u,v),x);
        }
        else
        {
            scanf("%d",&u);
            printf("%lld\n",ask(u));
        }
    }
}
int main()
{
    //freopen("data.in","r",stdin);
    //freopen("wr.out","w",stdout);
    init();
    work();
    return 0;
}


#include <cstdio>
#define ll long long
#define ls id<<1
#define rs id<<1|1
const int N=100010;
int head[N],to[N<<1],Next[N<<1],cnt;
void add(int u,int v)
{
    to[++cnt]=v;Next[cnt]=head[u];head[u]=cnt;
}
int f[N][20],dfn[N],dep[N],siz[N],dfs_clock,root;
void dfs(int now)
{
    dfn[now]=++dfs_clock;
    siz[now]++;
    for(int i=head[now];i;i=Next[i])
    {
        int v=to[i];
        if(f[now][0]!=v)
        {
            dep[v]=dep[now]+1;
            f[v][0]=now;
            dfs(v);
            siz[now]+=siz[v];
        }
    }
}
ll sum[N<<2],lazy[N<<2],dat[N];
int n,q;
void updata(int id)
{
    sum[id]=sum[ls]+sum[rs];
}
void push_down(int id,ll L,ll R)
{
    if(!lazy[id]) return;
    if(L!=R)
    {
        ll mid=L+R>>1;
        sum[ls]+=(mid+1-L)*lazy[id];
        sum[rs]+=(R-mid)*lazy[id];
        lazy[ls]+=lazy[id];
        lazy[rs]+=lazy[id];
    }
    lazy[id]=0;
}
void build(int id,int l,int r)
{
    if(l==r)
    {
        sum[id]=dat[dfn[l]];
        return;
    }
    int mid=l+r>>1;
    build(ls,l,mid);
    build(rs,mid+1,r);
    updata(id);
}
void change(int id,ll l,ll r,ll L,ll R,ll delta)
{
    push_down(id,L,R);
    if(l==L&&r==R)
    {
        sum[id]+=(R+1-L)*delta;
        lazy[id]+=delta;
        return;
    }
    ll mid=L+R>>1;
    if(r<=mid) change(ls,l,r,L,mid,delta);
    else if(l>mid) change(rs,l,r,mid+1,R,delta);
    else change(ls,l,mid,L,mid,delta),change(rs,mid+1,r,mid+1,R,delta);
    updata(id);
}
ll query(int id,ll l,ll r,ll L,ll R)
{
    push_down(id,L,R);
    if(l==L&&r==R) return sum[id];
    ll mid=L+R>>1;
    if(r<=mid) return query(ls,l,r,L,mid);
    else if(l>mid) return query(rs,l,r,mid+1,R);
    else return query(ls,l,mid,L,mid)+query(rs,mid+1,r,mid+1,R);
}
void init()
{
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++) scanf("%lld",dat+i);
    for(int u,v,i=1;i<n;i++)
    {
        scanf("%d%d",&u,&v);
        add(u,v),add(v,u);
    }
    dfs(root=1);
    for(int j=1;j<=18;j++)
        for(int i=1;i<=n;i++)
            f[i][j]=f[f[i][j-1]][j-1];
    build(1,1,n);
}
void Swap(int &x,int &y)
{
    int tmp=x;
    x=y;
    y=tmp;
}
int LCA0(int x,int y)//原树的LCA
{
    if(dep[x]<dep[y]) Swap(x,y);
    for(int i=18;~i;i--)
        if(dep[f[x][i]]>=dep[y])
            x=f[x][i];
    if(x==y) return x;
    for(int i=18;~i;i--)
        if(f[x][i]!=f[y][i])
            x=f[x][i],y=f[y][i];
    return f[x][0];
}
int LCA(int x,int y)//换根后的LCA
{
    int z1=LCA0(x,root),z2=LCA0(y,root);
    if(z1==z2) return LCA0(x,y);
    else return dep[z1]>dep[z2]?z1:z2;
}
bool in(int x)//询问x是否在以root为根的子树里
{
    if(dfn[x]>=dfn[root]&&dfn[x]<=dfn[root]+siz[root]-1) return true;
    return false;
}
int querys(int x)//询问根到x位置上x的那个儿子
{
    int y=root;
    for(int i=18;~i;i--)
        if(dep[f[y][i]]>dep[x])
            y=f[y][i];
    return y;
}
void modify(int x,ll delta)//给以x为根的子树加上delta
{
    if(in(x))
    {
        if(x!=root) change(1,dfn[x],dfn[x]+siz[x]-1,1,n,delta);
        else change(1,1,n,1,n,delta);
        return;
    }
    change(1,1,n,1,n,delta);
    int son=querys(x);
    change(1,dfn[son],dfn[son]+siz[son]-1,1,n,-delta);
}
ll ask(int x)//询问新根下子树权值和
{
    if(in(x))
        return query(1,dfn[x],dfn[x]+siz[x]-1,1,n);
    ll ans=0;
    ans+=query(1,1,n,1,n);
    int son=querys(x);
    ans-=query(1,dfn[son],dfn[son]+siz[son]-1,1,n);
    return ans;
}
void work()
{
    ll x;
    for(int opt,u,v,i=1;i<=q;i++)
    {
        scanf("%d",&opt);
        if(opt==1)
        {
            scanf("%d",&u);
            root=u;
        }
        else if(opt==2)
        {
            scanf("%d%d%lld",&u,&v,&x);
            modify(LCA(u,v),x);
        }
        else
        {
            scanf("%d",&u);
            printf("%lld\n",ask(u));
        }
    }
}
int main()
{
    init();
    work();
    return 0;
}


#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
vector<int> e[100010];
int st[100010], nd[100010], c, deg[100010], par[17][100010];
void dfs(int v, int p = -1) {
	st[v] = c++;
	for (int i = 0; i < e[v].size(); i++) {
		int w = e[v][i];
		if (p == w) continue;
		deg[w] = deg[v] + 1;
		dfs(w, v);
		par[0][w] = v;
	}
	nd[v] = c;
}
int lca(int u, int v) {
	if (deg[u] > deg[v]) {
		return lca(v, u);
	}
	int k = deg[v] - deg[u];
	for (int i = 0; i < 17; i++) {
		if (k >> i & 1) {
			v = par[i][v];
		}
	}
	if (u == v) return u;
	for (int i = 16; i >= 0; i--) {
		if (par[i][u] != par[i][v]) {
			u = par[i][u];
			v = par[i][v];
		}
	}
	return par[0][u];
}
int nlca(int u, int v) {
	int k = deg[v] - deg[u] - 1;
	if (k <= 0) return v;
	for (int i = 0; i < 17; i++) {
		if (k >> i & 1) {
			v = par[i][v];
		}
	}
	return v;
}
inline int isin(int u, int v) {
	return st[u] <= st[v] && st[v] < nd[u];
}
const int N = 1 << 17;
long long b[1<<18], lv[1<<18];
inline void push(int p, int h) {
	if (lv[p]) {
		b[p+p] += lv[p] * h / 2;
		b[p+p+1] += lv[p] * h / 2;
		lv[p+p] += lv[p];
		lv[p+p+1] += lv[p];
		lv[p] = 0;
	}
}
void add(int l, int r, int x, int L = 0, int R = N, int p = 1) {
	if (r <= L || R <= l) return;
	if (l <= L && R <= r) {
		b[p] += (long long)x * (R - L);
		lv[p] += x;
		return;
	}
	push(p, R - L);
	add(l, r, x, L, (L+R)/2, p + p);
	add(l, r, x, (L+R)/2, R, p + p + 1);
	b[p] = b[p+p] + b[p+p+1];
}
long long sum(int l, int r, int L = 0, int R = N, int p = 1) {
	if (r <= L || R <= l) return 0;
	if (l <= L && R <= r) {
		return b[p];
	}
	push(p, R - L);
	long long res = sum(l, r, L, (L+R)/2, p + p) + sum(l, r, (L+R)/2, R, p + p + 1);
	return res;
}
int a[100010];
int main() {
	int n, q;
	scanf("%d%d", &n, &q);
	for (int i = 0; i < n; i++) {
		scanf("%d", &a[i]);
	}
	for (int i = 0; i < n - 1; i++) {
		int x, y;
		scanf("%d%d", &x, &y);
		--x; --y;
		e[x].push_back(y);
		e[y].push_back(x);
	}
	dfs(0);
	for (int i = 0; i < 16; i++) {
		for (int j = 0; j < n; j++) {
			par[i+1][j] = par[i][par[i][j]];
		}
	}
	for (int i = 0; i < n; i++) {
		b[st[i]+N] = a[i];
	}
	for (int i = N - 1; i > 0; i--) {
		b[i] = b[i+i] + b[i+i+1];
	}
	int r = 0;
	while (q--) {
		int t, u, v, x;
		scanf("%d%d", &t, &v);
		--v;
		if (t == 2) {
			scanf("%d%d", &u, &x);
			--u;
			if (u == r || v == r) {
				add(0, c, x);
			} else if (isin(r, u) ^ isin(r, v)) {
				add(0, c, x);
			} else if (isin(r, u) && isin(r, v)) {
				int p = lca(u, v);
				if (p == r) {
					add(0, c, x);
				} else {
					add(st[p], nd[p], x);
				}
			} else {
				int p = lca(u, v);
				if (isin(p, r)) {
					int q = lca(r, u);
					p = lca(r, v);
					if (deg[p] < deg[q]) {
						p = q;
					}
					q = nlca(p, r);
					add(0, c, x);
					add(st[q], nd[q], -x);
				} else {
					add(st[p], nd[p], x);
				}
			}
		} else if (t == 1) {
			r = v;
		} else {
			long long ans;
			if (v == r) {
				ans = sum(0, c);
			} else if (isin(v, r)) {
				u = nlca(v, r);
				ans = sum(0, c) - sum(st[u], nd[u]);
			} else {
				ans = sum(st[v], nd[v]);
			}
			printf("%I64d\n", ans);
		}
	}
	return 0;
}


#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
vector<int> e[100010];
int st[100010], nd[100010], c, deg[100010], par[17][100010];
void dfs(int v, int p = -1) {
	st[v] = c++;
	for (int i = 0; i < e[v].size(); i++) {
		int w = e[v][i];
		if (p == w) continue;
		deg[w] = deg[v] + 1;
		dfs(w, v);
		par[0][w] = v;
	}
	nd[v] = c;
}
int lca(int u, int v) {
	if (deg[u] > deg[v]) {
		return lca(v, u);
	}
	int k = deg[v] - deg[u];
	for (int i = 0; i < 17; i++) {
		if (k >> i & 1) {
			v = par[i][v];
		}
	}
	if (u == v) return u;
	for (int i = 16; i >= 0; i--) {
		if (par[i][u] != par[i][v]) {
			u = par[i][u];
			v = par[i][v];
		}
	}
	return par[0][u];
}
int nlca(int u, int v) {
	if (deg[u] > deg[v]) {
		return nlca(v, u);
	}
	int k = deg[v] - deg[u] - 1;
	for (int i = 0; i < 17; i++) {
		if (k >> i & 1) {
			v = par[i][v];
		}
	}
	return v;
}
inline int isin(int u, int v) {
	return st[u] <= st[v] && st[v] < nd[u];
}
const int N = 1 << 17;
long long b[1<<18], lv[1<<18];
inline void push(int p, int h) {
	if (lv[p]) {
		b[p+p] += lv[p] * h / 2;
		b[p+p+1] += lv[p] * h / 2;
		lv[p+p] += lv[p];
		lv[p+p+1] += lv[p];
		lv[p] = 0;
	}
}
void add(int l, int r, int x, int L = 0, int R = N, int p = 1) {
	if (r <= L || R <= l) return;
	if (l <= L && R <= r) {
		b[p] += (long long)x * (R - L);
		lv[p] += x;
		return;
	}
	push(p, R - L);
	add(l, r, x, L, (L+R)/2, p + p);
	add(l, r, x, (L+R)/2, R, p + p + 1);
	b[p] = b[p+p] + b[p+p+1];
}
long long sum(int l, int r, int L = 0, int R = N, int p = 1) {
	if (r <= L || R <= l) return 0;
	if (l <= L && R <= r) {
		return b[p];
	}
	push(p, R - L);
	long long res = sum(l, r, L, (L+R)/2, p + p) + sum(l, r, (L+R)/2, R, p + p + 1);
	return res;
}
int a[100010];
int main() {
	int n, q;
	scanf("%d%d", &n, &q);
	for (int i = 0; i < n; i++) {
		scanf("%d", &a[i]);
	}
	for (int i = 0; i < n - 1; i++) {
		int x, y;
		scanf("%d%d", &x, &y);
		--x; --y;
		e[x].push_back(y);
		e[y].push_back(x);
	}
	dfs(0);
	for (int i = 0; i < 16; i++) {
		for (int j = 0; j < n; j++) {
			par[i+1][j] = par[i][par[i][j]];
		}
	}
	for (int i = 0; i < n; i++) {
		b[st[i]+N] = a[i];
	}
	for (int i = N - 1; i > 0; i--) {
		b[i] = b[i+i] + b[i+i+1];
	}
	int r = 0;
	while (q--) {
		int t, u, v, x;
		scanf("%d%d", &t, &v);
		--v;
		if (t == 2) {
			scanf("%d%d", &u, &x);
			--u;
			if (u == r || v == r) {
				add(0, c, x);
			} else if (isin(r, u) ^ isin(r, v)) {
				add(0, c, x);
			} else if (isin(r, u) && isin(r, v)) {
				int p = lca(u, v);
				add(st[p], nd[p], x);
			} else {
				int p = lca(u, v);
				if (isin(p, r)) {
					int q = lca(r, u);
					p = lca(r, v);
					if (deg[p] < deg[q]) {
						p = q;
					}
					q = nlca(p, r);
					add(0, c, x);
					add(st[q], nd[q], -x);
				} else {
					add(st[p], nd[p], x);
				}
			}
		} else if (t == 1) {
			r = v;
		} else {
			long long ans;
			if (v == r) {
				ans = sum(0, c);
			} else if (isin(v, r)) {
				u = nlca(v, r);
				ans = sum(0, c) - sum(st[u], nd[u]);
			} else {
				ans = sum(st[v], nd[v]);
			}
			printf("%I64d\n", ans);
		}
	}
	return 0;
}


#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
vector<int> e[100010];
int st[100010], nd[100010], c, deg[100010], par[17][100010];
void dfs(int v, int p = -1) {
	st[v] = c++;
	for (int i = 0; i < e[v].size(); i++) {
		int w = e[v][i];
		if (p == w) continue;
		deg[w] = deg[v] + 1;
		dfs(w, v);
		par[0][w] = v;
	}
	nd[v] = c;
}
int lca(int u, int v) {
	if (deg[u] > deg[v]) {
		return lca(v, u);
	}
	int k = deg[v] - deg[u];
	for (int i = 0; i < 17; i++) {
		if (k >> i & 1) {
			v = par[i][v];
		}
	}
	if (u == v) return u;
	for (int i = 0; i < 17; i++) {
		if (par[i][u] != par[i][v]) {
			u = par[i][u];
			v = par[i][v];
		}
	}
	return par[0][u];
}
int nlca(int u, int v) {
	if (deg[u] > deg[v]) {
		return nlca(v, u);
	}
	int k = deg[v] - deg[u] - 1;
	for (int i = 0; i < 17; i++) {
		if (k >> i & 1) {
			v = par[i][v];
		}
	}
	return v;
}
inline int isin(int u, int v) {
	return st[u] <= st[v] && st[v] < nd[u];
}
const int N = 1 << 17;
long long b[1<<18], lv[1<<18];
inline void push(int p, int h) {
	if (lv[p]) {
		b[p+p] += lv[p] * h / 2;
		b[p+p+1] += lv[p] * h / 2;
		lv[p+p] += lv[p];
		lv[p+p+1] += lv[p];
		lv[p] = 0;
	}
}
void add(int l, int r, int x, int L = 0, int R = N, int p = 1) {
	if (r <= L || R <= l) return;
	if (l <= L && R <= r) {
		b[p] += (long long)x * (R - L);
		lv[p] += x;
		return;
	}
	push(p, R - L);
	add(l, r, x, L, (L+R)/2, p + p);
	add(l, r, x, (L+R)/2, R, p + p + 1);
	b[p] = b[p+p] + b[p+p+1];
}
long long sum(int l, int r, int L = 0, int R = N, int p = 1) {
	if (r <= L || R <= l) return 0;
	if (l <= L && R <= r) {
		return b[p];
	}
	push(p, R - L);
	long long res = sum(l, r, L, (L+R)/2, p + p) + sum(l, r, (L+R)/2, R, p + p + 1);
	return res;
}
int a[100010];
int main() {
	int n, q;
	scanf("%d%d", &n, &q);
	for (int i = 0; i < n; i++) {
		scanf("%d", &a[i]);
		b[i+N] = a[i];
	}
	for (int i = 0; i < n - 1; i++) {
		int x, y;
		scanf("%d%d", &x, &y);
		--x; --y;
		e[x].push_back(y);
		e[y].push_back(x);
	}
	for (int i = N - 1; i > 0; i--) {
		b[i] = b[i+i] + b[i+i+1];
	}
	dfs(0);
	for (int i = 0; i < 16; i++) {
		for (int j = 0; j < n; j++) {
			par[i+1][j] = par[i][par[i][j]];
		}
	}
	int r = 0;
	while (q--) {
		int t, u, v, x;
		scanf("%d%d", &t, &v);
		--v;
		if (t == 2) {
			scanf("%d%d", &u, &x);
			--u;
			if (u == r || v == r) {
				add(0, c, x);
			} else if (isin(r, u) ^ isin(r, v)) {
				add(0, c, x);
			} else if (isin(r, u) && isin(r, v)) {
				int p = lca(u, v);
				add(st[p], nd[p], x);
			} else {
				int p = lca(u, v);
				if (isin(p, r)) {
					int q = lca(r, u);
					p = lca(r, v);
					if (deg[p] < deg[q]) {
						p = q;
					}
					q = nlca(p, r);
					add(0, c, x);
					add(st[q], nd[q], -x);
				} else {
					add(st[p], nd[p], x);
				}
			}
		} else if (t == 1) {
			r = v;
		} else {
			long long ans;
			if (v == r) {
				ans = sum(0, c);
			} else if (isin(v, r)) {
				u = nlca(v, r);
				ans = sum(0, c) - sum(st[u], nd[u]);
			} else {
				ans = sum(st[v], nd[v]);
			}
			printf("%I64d\n", ans);
		}
	}
	return 0;
}


#include<bits/stdc++.h>

using namespace std;

typedef long long ll;

const int MAXN=3E5+10;

struct __edge{
    int v,nxt;
}Edge[MAXN<<1];

ll t[MAXN<<3],tag[MAXN<<3],val[MAXN];
int head[MAXN],cnt_e,siz[MAXN],pos[MAXN],dft,rt,rev[MAXN],n,q,jmp[MAXN][21],dep[MAXN];

inline void add(int u,int v)
{
    Edge[++cnt_e].v=v;
    Edge[cnt_e].nxt=head[u];
    head[u]=cnt_e;
    Edge[++cnt_e].v=u;
    Edge[cnt_e].nxt=head[v];
    head[v]=cnt_e;
}

void pushdown(int x,int l,int r)
{
    if(tag[x])
    {
        int mid=(l+r)>>1;
        t[x<<1]+=1ll*tag[x]*(mid-l+1);
        t[x<<1|1]+=1ll*tag[x]*(r-mid);
        tag[x<<1]+=tag[x];
        tag[x<<1|1]+=tag[x];
        tag[x]=0;
    }
}

void build(int x,int l,int r)
{
    if(l==r) return t[x]=val[rev[l]],void();
    int mid=(l+r)>>1;
    build(x<<1,l,mid);build(x<<1|1,mid+1,r);
    t[x]=t[x<<1]+t[x<<1|1];
}

void change(int x,int l,int r,int cl,int cr,int val)
{
    if(cl<=l&&r<=cr) return t[x]+=1ll*val*(r-l+1),tag[x]+=val,void();
    int mid=(l+r)>>1;pushdown(x,l,r);
    if(cl<=mid) change(x<<1,l,mid,cl,cr,val);
    if(cr>mid) change(x<<1|1,mid+1,r,cl,cr,val);
    t[x]=t[x<<1]+t[x<<1|1];
}

ll query(int x,int l,int r,int ql,int qr)
{
    if(ql<=l&&r<=qr) return t[x];
    int mid=(l+r)>>1;ll ret=0;pushdown(x,l,r);
    if(ql<=mid) ret+=query(x<<1,l,mid,ql,qr);
    if(qr>mid)  ret+=query(x<<1|1,mid+1,r,ql,qr);
    return ret;
}

void dfs(int x,int fa)
{
    pos[x]=++dft;siz[x]=1;
    jmp[x][0]=fa;dep[x]=dep[fa]+1;
    rev[dft]=x;
    for(int i=head[x];i;i=Edge[i].nxt)
        if(Edge[i].v!=fa)
            dfs(Edge[i].v,x),siz[x]+=siz[Edge[i].v];
}

void init()
{
    for(int j=1;j<=20;j++)
        for(int i=1;i<=n;i++)
            jmp[i][j]=jmp[jmp[i][j-1]][j-1];
}

inline int __lca(int x,int y)
{
    if(dep[x]>dep[y]) swap(x,y);
    for(int i=20;~i;i--)
        if(dep[jmp[y][i]]>=dep[x])
            y=jmp[y][i];
    if(x==y) return x;
    for(int i=20;~i;i--)
        if(jmp[x][i]!=jmp[y][i])
            x=jmp[x][i],y=jmp[y][i];
    return jmp[x][0];
}

inline pair<int,int> __lca_p(int x,int y)
{
    bool flag=0;
    if(dep[x]>dep[y]) swap(x,y),flag=1;
    for(int i=20;~i;i--)
        if(dep[jmp[y][i]]>=dep[x])
            y=jmp[y][i];
    if(x==y) return make_pair(x,x);
    for(int i=20;~i;i--)
        if(jmp[x][i]!=jmp[y][i])
            x=jmp[x][i],y=jmp[y][i];
    if(flag) swap(x,y);
    return make_pair(x,y);
}

inline int fa_son(int x,int fa)
{
    for(int i=20;~i;i--)
        if(dep[jmp[x][i]]>dep[fa])
            x=jmp[x][i];
    return x;
}

inline bool inside(int x,int y){return pos[x]<=pos[y]&&pos[y]<=pos[x]+siz[x]-1;}// y in x

inline void makeroot(int x){rt=x;}

inline int lca(int x,int y,bool flag)
{
    int a=__lca(rt,x),b=__lca(rt,y);
    if(a==b) return __lca(x,y);
    else return dep[a]>dep[b]?a:b;
}

inline void st_plus(int x,int val)
{
    if(x==rt) change(1,1,n,1,n,val);
    else if(inside(x,rt))
    {
        int t=fa_son(rt,x);
        change(1,1,n,1,n,val);change(1,1,n,pos[t],pos[t]+siz[t]-1,-val);
    }
    else change(1,1,n,pos[x],pos[x]+siz[x]-1,val);
}

inline ll st_query(int x)
{
    if(x==rt) return query(1,1,n,1,n);
    else if(inside(x,rt))
    {
        int t=fa_son(rt,x);
        return query(1,1,n,1,n)-query(1,1,n,pos[t],pos[t]+siz[t]-1);
    }
    else return query(1,1,n,pos[x],pos[x]+siz[x]-1);
}

int main()
{
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++) cin>>val[i];
    for(int i=1,u,v;i<n;i++) scanf("%d%d",&u,&v),add(u,v);
    dfs(1,0);rt=1;init();
    build(1,1,n);
    for(int i=1,op,x,y,z;i<=q;i++)
    {
        scanf("%d",&op);
        if(op==1) scanf("%d",&x),makeroot(x);
        else if(op==2) scanf("%d%d%d",&x,&y,&z),st_plus(lca(x,y,0),z);
        else if(op==3) scanf("%d",&x),cout<<st_query(x)<<endl;
    }
}


#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define int long long
#define pr(x) cout<<#x<<":"<<x<<endl
const int maxn = 1e5+7;
int n,q;
struct edge{
    int u,v,nxt;
}es[maxn<<1];
int head[maxn];
int tot = 0;
void addedge(int u,int v){
    es[tot].u = u,es[tot].v = v,es[tot].nxt = head[u];
    head[u] = tot++;
}
int fa[maxn][22],dep[maxn];
int idx = 0,IN[maxn],OUT[maxn];
int segtree[maxn<<3],addmark[maxn<<3];
void init(){
    memset(fa,0,sizeof(fa));
    memset(head,-1,sizeof(head));
    memset(IN,0,sizeof(IN));
    memset(OUT,0,sizeof(OUT));
    memset(dep,0,sizeof(dep));
    tot = idx = 0;
}
void dfs(int u,int myfa,int dp){
    dep[u] = dp;
    IN[u] = ++idx;
    for(int e = head[u];e != -1;e = es[e].nxt){
        int v = es[e].v;
        if(v == myfa) continue;
        fa[v][0] = u;
        dfs(v,u,dp+1);
    }
    OUT[u] = ++idx;
}
void pushdown(int rt,int lft,int rgt){
    if(addmark[rt]){
        int mid = (lft + rgt)/2;
        addmark[2*rt] += addmark[rt];
        addmark[2*rt+1] += addmark[rt];
        segtree[2*rt] += addmark[rt]*(mid-lft+1);
        segtree[2*rt+1] += addmark[rt]*(rgt-mid);
        addmark[rt] = 0;
    }
}
void pushup(int rt){
    segtree[rt] = segtree[rt*2] + segtree[rt*2+1];
}
int val[maxn];
/*
void build(int rt,int L,int R){
    if(R == L) {
        segtree[rt] = val[L];
    }
    else{
        build(L,mid);build(mid+1,R);
    }
}*/
void ins(int rt,int lft,int rgt,int L,int R,int adv){
    if(rgt < L || lft > R) return ;
    if(L <= lft && R >= rgt) {
        segtree[rt] += (rgt-lft+1)*adv;
        addmark[rt] += adv;
        return ;
    }
    int mid = (lft + rgt) / 2;
    pushdown(rt,lft,rgt);
    ins(rt*2,lft,mid,L,R,adv);
    ins(rt*2+1,mid+1,rgt,L,R,adv);
    pushup(rt);
}
int ask(int rt,int lft,int rgt,int L,int R){
    if(rgt < L || lft > R) return 0;
    if(L <= lft && R >= rgt) return segtree[rt];
    pushdown(rt,lft,rgt);
    int mid = (lft + rgt)/2;
    return ask(rt*2,lft,mid,L,R) + ask(rt*2+1,mid+1,rgt,L,R);
}
void makelca(){
    for(int i = 1;i < 20;++i){
        for(int u = 1;u <= n;++u){
            fa[u][i] = fa[fa[u][i-1]][i-1];
        }
    }
}
int lca(int u,int v){
    if(dep[u] < dep[v]) swap(u,v);
    int dpc = dep[u] - dep[v];
    if(dpc){
        int t = 0;
        while(dpc){
            if(dpc & 1)
                u = fa[u][t];
            t++;
            dpc >>= 1;
        }
    }
    if(u == v) return u;
    for(int i = 19;u != v && i >= 0;--i ){
        if(fa[u][i] != fa[v][i]) {
            u = fa[u][i];v = fa[v][i];
        }
    }
    return fa[u][0];
}

int root = 1;
main(){
    init();
    scanf("%lld%lld",&n,&q);
    for(int i = 1;i <= n;++i){
        scanf("%lld",&val[i]);
    }
    for(int i = 0;i < n-1;++i){
        int u,v;scanf("%lld%lld",&u,&v);
        addedge(u,v);
        addedge(v,u);
    }
    dfs(1,-1,0);
    makelca();
    for(int i = 1;i <= n;++i){
        ins(1,1,2*n,IN[i],IN[i],val[i]);
        ins(1,1,2*n,OUT[i],OUT[i],val[i]);
    }
    //计算lca

    for(int i = 0;i < q;++i){
        int op ;
        scanf("%lld",&op);
        if(op == 1){
            scanf("%lld",&root);
        }
        else if(op == 2){
            int u,v,x;scanf("%lld%lld%lld",&u,&v,&x);
            int rt = lca(u,v)^lca(u,root)^lca(root,v);
            if(rt == root) ins(1,1,2*n,1,2*n,x);
            else if(lca(rt,root) != rt) ins(1,1,2*n,IN[rt],OUT[rt],x);
            else{
                int dpc = dep[root]-dep[rt]-1;
                int t = 0;
                int tmp = root;

                while(dpc){
                    if(dpc&1)
                        tmp = fa[tmp][t];
                    t++;
                    dpc >>= 1;
                }
                //cout<<tmp<<' '<<IN[tmp]<<' '<<OUT[tmp]<<endl;
                ins(1,1,2*n,1,2*n,x);
                ins(1,1,2*n,IN[tmp],OUT[tmp],-x);
            }
        }
        else if(op == 3){
            int v;scanf("%lld",&v);
            if(v == root){
                printf("%lld\n",ask(1,1,2*n,1,2*n)/2);
            }
            else if(lca(v,root) != v){
                printf("%lld\n",ask(1,1,2*n,IN[v],OUT[v])/2);
            }
            else{
                int tmp = root;
                int dpc = dep[root]-1-dep[v];
                int t = 0;
                while(dpc){
                    if(dpc&1)
                        tmp = fa[tmp][t];
                    ++t;
                    dpc >>= 1;
                }
                int ans = (ask(1,1,2*n,1,2*n)-ask(1,1,2*n,IN[tmp],OUT[tmp]))/2;
                printf("%lld\n",ans);
            }
        }
    }
    //return 0;
}


#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,sse3,sse4,popcnt,abm,mmx")
#include<bits/stdc++.h>
#define fo(i, n) for(int i = 1; i <= (n); i ++)
#define out(x) cout << #x << " = " << x << "\n"
using namespace std;
typedef long long ll;
#define R register
//by piano
template<typename tp> inline void read(tp &x) {
  x = 0; char c = getchar(); bool f = 0;
  for(; c < '0' || c > '9'; f |= (c == '-'), c = getchar());
  for(; c >= '0' && c <= '9'; x = (x << 3) + (x << 1) + c - '0', c = getchar());
  if(f) x = -x;
}
const int N = 2e5 + 233, M = 1e6 + 111233;
char str[N];
int w[N], cnt[M];
struct E {
  int nxt, to;
}e[N << 2];
int e_cnt = 0, head[N];
int sz[N], f[N], dep[N], book[N];
ll sum[N];
int n, m, ans = 0, all, rt;
inline void add(int u, int v) {
  e[++ e_cnt] = (E) {head[u], v}; head[u] = e_cnt;
}

inline void frt(int u, int fa) {
  sz[u] = 1; f[u] = 0;
  for(R int i = head[u]; i; i = e[i].nxt) {
    R int v = e[i].to;
    if(v != fa && !book[v]) {
      frt(v, u);
      sz[u] += sz[v];
      f[u] = max(f[u], sz[v]);
    }
  }
  f[u] = max(f[u], all - sz[u]);
  if(!rt || f[rt] > f[u]) rt = u;
}

inline void go(int u, int fa, int s, int f) {
  cnt[s ^= 1 << w[u]] += f;
  for(R int i = head[u]; i; i = e[i].nxt) {
    R int v = e[i].to;
    if(v != fa && !book[v])
      go(v, u, s, f);
  }
}

inline ll calc(int u, int fa, int s) {
  R ll ans = cnt[s ^= 1 << w[u]];
  for(R int i = 0; i < 20; i ++)
    ans += cnt[s ^ (1 << i)];
  for(R int i = head[u]; i; i = e[i].nxt) {
    R int v = e[i].to;
    if(v != fa && !book[v]) {
      ans += calc(v, u, s);
    }
  }
  sum[u] += ans;
  return ans;
}

inline void work(int u, int fa) {
  book[u] = 1;
  R ll res = 0;
  go(u, fa, 0, 1);
  for(R int i = head[u]; i; i = e[i].nxt) {
    R int v = e[i].to;
    if(v != fa && !book[v]) {
      go(v, u, 1 << w[u], -1);
      res += calc(v, u, 0);
      go(v, u, 1 << w[u], 1);
    }
  }
  for(R int i = 0; i < 20; i ++)
    res += cnt[1 << i];
  res += cnt[0];
  sum[u] += res / 2;
  go(u, fa, 0, -1);
  for(R int i = head[u]; i; i = e[i].nxt) {
    R int v = e[i].to;
    if(v != fa && !book[v]) {
      all = sz[v];
      frt(v, rt = 0);
      work(rt, u);
    }
  }
}

main(void) {
  // freopen("2.in", "r", stdin);
  // freopen("1.out", "w", stdout);
  read(n);
  for(int i = 1; i <= n - 1; i ++) {
    int u, v;
    read(u); read(v);
    add(u, v); add(v, u);
  }
  scanf("%s", str + 1);
  for(int i = 1; i <= n; i ++)
    w[i] = str[i] - 'a';
  all = n;
  frt(1, rt = 0);
  work(rt, 0);
  for(int i = 1; i <= n; i ++)
    printf("%lld%c", sum[i] + 1, "  "[i == n]);
  puts("");
}


#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
typedef long long LL;
using namespace std;
LL RD(){
    LL out = 0,flag = 1;char c = getchar();
    while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
    while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
    return flag * out;
    }
const LL maxn = 200019,INF = 1e9 + 19;
LL head[maxn],nume = 1;
struct Node{
    LL v,dis,nxt;
    }E[maxn << 2];
void add(LL u,LL v,LL dis){
    E[++nume].nxt = head[u];
    E[nume].v = v;
    E[nume].dis = dis;
    head[u] = nume;
    }
LL num, na;
LL dep[maxn], size[maxn], fa[maxn], wson[maxn], top[maxn], pos[maxn], ori[maxn], cnt;
LL v[maxn];
void dfs1(LL id, LL F){
	size[id] = 1;
	for(LL i = head[id];i;i = E[i].nxt){
		LL v = E[i].v;
		if(v == F)continue;
		dep[v] = dep[id] + 1;
		fa[v] = id;
		dfs1(v, id);
		size[id] += size[v];
		if(size[v] > size[wson[id]])wson[id] = v;
		}
	}
void dfs2(LL id, LL TP){
	pos[id] = ++cnt;
	ori[cnt] = id;
	top[id] = TP;
	if(!wson[id])return ;
	dfs2(wson[id], TP);
	for(LL i = head[id];i;i = E[i].nxt){
		LL v = E[i].v;
		if(v == fa[id] || v == wson[id])continue;
		dfs2(v, v);
		}
	}
#define lid (id << 1)
#define rid (id << 1) | 1
struct seg_tree{
	LL l, r;
	LL lazy, sum;
	}tree[maxn << 2];
void pushup(LL id){tree[id].sum = tree[lid].sum + tree[rid].sum;}
void pushdown(LL id){
	if(tree[id].lazy){
		LL val = tree[id].lazy;
		tree[lid].lazy += val;
		tree[rid].lazy += val;
		tree[lid].sum += (tree[lid].r - tree[lid].l + 1) * val;
		tree[rid].sum += (tree[rid].r - tree[rid].l + 1) * val;
		tree[id].lazy = 0;
		}
	}
void build(LL id, LL l, LL r){
	tree[id].l = l, tree[id].r = r;
	if(l == r){
		tree[id].sum = v[ori[l]];
		return ;
		}
	LL mid = (l + r) >> 1;
	build(lid, l, mid), build(rid, mid + 1, r);
	pushup(id);
	}
void update(LL id, LL val, LL l, LL r){
	pushdown(id);
	if(tree[id].l == l && tree[id].r == r){
		tree[id].sum += (tree[id].r - tree[id].l + 1) * val;
		tree[id].lazy += val;
		return ;
		}
	LL mid = (tree[id].l + tree[id].r) >> 1;
	if(mid < l)update(rid, val, l, r);
	else if(mid >= r)update(lid, val, l, r);
	else update(lid, val, l, mid), update(rid, val, mid + 1, r);
	pushup(id);
	}
LL query(LL id, LL l ,LL r){
	pushdown(id);
	if(tree[id].l == l && tree[id].r == r){
		return tree[id].sum;
		}
	LL mid = (tree[id].l + tree[id].r) >> 1;
	if(mid < l)return query(rid, l, r);
	else if(mid >= r)return query(lid, l, r);
	else return query(lid, l, mid) + query(rid, mid + 1, r);
	}
LL root = 1, jump[maxn][25];
void get_jump(){
	for(LL i = 1;i <= num;i++)jump[i][0] = fa[i];
	for(LL i = 1;i <= 19;i++){
		for(LL j = 1;j <= num;j++){
			jump[j][i] = jump[jump[j][i - 1]][i - 1];
			}
		}
	}
LL LCA(LL x, LL y){
	if(dep[x] < dep[y])swap(x, y);
	for(LL i = 19;i >= 0;i--)if(dep[jump[x][i]] >= dep[y])x = jump[x][i];
	if(x == y)return x;
	for(LL i = 19;i >= 0;i--)if(jump[x][i] != jump[y][i])x = jump[x][i], y = jump[y][i];
	return jump[x][0];
	}
LL real_LCA(LL x, LL y){
	LL lca1 = LCA(x, y), lca2 = LCA(x, root), lca3 = LCA(y, root);
	LL lca = dep[lca1] > dep[lca2] ? lca1 : lca2;
	return dep[lca] > dep[lca3] ? lca : lca3;
	}
LL son_LCA(LL x, LL y = root){
	if(dep[x] >= dep[y])return -1;
	for(LL i = 19;i >= 0;i--)if(dep[jump[y][i]] >= dep[x] + 1)y = jump[y][i];
	if(fa[y] == x)return y;
	return -1;
	}
void change_root(){root = RD();}
void uprange(){
	LL x = RD(), y = RD(), val = RD();
	LL lca = real_LCA(x, y);//printf("real_LCA=%d\n", lca);
	if(lca == root){update(1, val, pos[1], pos[1] + size[1] - 1);return ;}
	LL son = son_LCA(lca);//printf("son=%d\n", son);
	if(son == -1){update(1, val, pos[lca], pos[lca] + size[lca] - 1);return ;}
	update(1, val, pos[1], pos[1] + size[1] - 1);
	update(1,-val, pos[son], pos[son] + size[son] - 1);
	}
void get_sum(){
	LL x = RD();
	if(x == root){printf("%lld\n", query(1, pos[1], pos[1] + size[1] - 1));return ;}
	LL son = son_LCA(x);
	if(son == -1){printf("%lld\n", query(1, pos[x], pos[x] + size[x] - 1));return ;}
	printf("%lld\n", query(1, pos[1], pos[1] + size[1] - 1) - query(1, pos[son], pos[son] + size[son] - 1));
	}
int main(){
	num = RD();na = RD();
	for(LL i = 1;i <= num;i++)v[i] = RD();
	for(LL i = 1;i <= num - 1;i++){
		LL u = RD(), v = RD();
		add(u, v, 1), add(v, u, 1);
		}
	dep[1] = 1;
	dfs1(1, -1), dfs2(1, 1);
	build(1, 1, num);
	get_jump();
	for(LL i = 1;i <= na;i++){
		LL cmd = RD();
		if(cmd == 1)change_root();
		else if(cmd == 2)uprange();
		else get_sum();
		}
	return 0;
	}


#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
typedef long long LL;
using namespace std;
LL RD(){
    LL out = 0,flag = 1;char c = getchar();
    while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
    while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
    return flag * out;
    }
const LL maxn = 1000019,INF = 1e9 + 19;
LL head[maxn],nume = 1;
struct Node{
    LL v,dis,nxt;
    }E[maxn << 3];
void add(LL u,LL v,LL dis){
    E[++nume].nxt = head[u];
    E[nume].v = v;
    E[nume].dis = dis;
    head[u] = nume;
    }
LL num, na;
LL dep[maxn], size[maxn], fa[maxn], wson[maxn], top[maxn], pos[maxn], ori[maxn], cnt;
LL v[maxn];
void dfs1(LL id, LL F){
	size[id] = 1;
	for(LL i = head[id];i;i = E[i].nxt){
		LL v = E[i].v;
		if(v == F)continue;
		dep[v] = dep[id] + 1;
		fa[v] = id;
		dfs1(v, id);
		size[id] += size[v];
		if(size[v] > size[wson[id]])wson[id] = v;
		}
	}
void dfs2(LL id, LL TP){
	pos[id] = ++cnt;
	ori[cnt] = id;
	top[id] = TP;
	if(!wson[id])return ;
	dfs2(wson[id], TP);
	for(LL i = head[id];i;i = E[i].nxt){
		LL v = E[i].v;
		if(v == fa[id] || v == wson[id])continue;
		dfs2(v, v);
		}
	}
#define lid (id << 1)
#define rid (id << 1) | 1
struct seg_tree{
	LL l, r;
	LL lazy, sum;
	}tree[maxn << 2];
void pushup(LL id){tree[id].sum = tree[lid].sum + tree[rid].sum;}
void pushdown(LL id){
	if(tree[id].lazy){
		LL val = tree[id].lazy;
		tree[lid].lazy += val;
		tree[rid].lazy += val;
		tree[lid].sum += (tree[lid].r - tree[lid].l + 1) * val;
		tree[rid].sum += (tree[rid].r - tree[rid].l + 1) * val;
		tree[id].lazy = 0;
		}
	}
void build(LL id, LL l, LL r){
	tree[id].l = l, tree[id].r = r;
	if(l == r){
		tree[id].sum = v[ori[l]];
		return ;
		}
	LL mid = (l + r) >> 1;
	build(lid, l, mid), build(rid, mid + 1, r);
	pushup(id);
	}
void update(LL id, LL val, LL l, LL r){
	pushdown(id);
	if(tree[id].l == l && tree[id].r == r){
		tree[id].sum += (tree[id].r - tree[id].l + 1) * val;
		tree[id].lazy += val;
		return ;
		}
	LL mid = (tree[id].l + tree[id].r) >> 1;
	if(mid < l)update(rid, val, l, r);
	else if(mid >= r)update(lid, val, l, r);
	else update(lid, val, l, mid), update(rid, val, mid + 1, r);
	pushup(id);
	}
LL query(LL id, LL l ,LL r){
	pushdown(id);
	if(tree[id].l == l && tree[id].r == r){
		return tree[id].sum;
		}
	LL mid = (tree[id].l + tree[id].r) >> 1;
	if(mid < l)return query(rid, l, r);
	else if(mid >= r)return query(lid, l, r);
	else return query(lid, l, mid) + query(rid, mid + 1, r);
	}
LL root = 1, jump[maxn][25];
void get_jump(){
	for(LL i = 1;i <= num;i++)jump[i][0] = fa[i];
	for(LL i = 1;i <= 19;i++){
		for(LL j = 1;j <= num;j++){
			jump[j][i] = jump[jump[j][i - 1]][i - 1];
			}
		}
	}
LL LCA(LL x, LL y){
	if(dep[x] < dep[y])swap(x, y);
	for(LL i = 19;i >= 0;i--)if(dep[jump[x][i]] >= dep[y])x = jump[x][i];
	if(x == y)return x;
	for(LL i = 19;i >= 0;i--)if(jump[x][i] != jump[y][i])x = jump[x][i], y = jump[y][i];
	return jump[x][0];
	}
LL real_LCA(LL x, LL y){
	LL lca1 = LCA(x, y), lca2 = LCA(x, root), lca3 = LCA(y, root);
	LL lca = dep[lca1] > dep[lca2] ? lca1 : lca2;
	return dep[lca] > dep[lca3] ? lca : lca3;
	}
LL son_LCA(LL x, LL y = root){
	if(dep[x] >= dep[y])return -1;
	for(LL i = 19;i >= 0;i--)if(dep[jump[y][i]] >= dep[x] + 1)y = jump[y][i];
	if(fa[y] == x)return y;
	return -1;
	}
void change_root(){root = RD();}
void uprange(){
	LL x = RD(), y = RD(), val = RD();
	LL lca = real_LCA(x, y);//prLLf("real_LCA=%d\n", lca);
	if(lca == root){update(1, val, pos[1], pos[1] + size[1] - 1);return ;}
	LL son = son_LCA(lca);//prLLf("son=%d\n", son);
	if(son == -1){update(1, val, pos[lca], pos[lca] + size[lca] - 1);return ;}
	update(1, val, pos[1], pos[1] + size[1] - 1);
	update(1,-val, pos[son], pos[son] + size[son] - 1);
	}
void get_sum(){
	LL x = RD();
	LL son = son_LCA(x);
	if(son == -1){printf("%lld\n", query(1, pos[x], pos[x] + size[x] - 1));return ;}
	printf("%lld\n", query(1, pos[1], pos[1] + size[1] - 1) - query(1, pos[son], pos[son] + size[son] - 1));
	}
int main(){
	num = RD();na = RD();
	for(LL i = 1;i <= num;i++)v[i] = RD();
	for(LL i = 1;i <= num - 1;i++){
		LL u = RD(), v = RD();
		add(u, v, 1), add(v, u, 1);
		}
	dep[1] = 1;
	dfs1(1, -1), dfs2(1, 1);
	build(1, 1, num);
	get_jump();
	for(LL i = 1;i <= na;i++){
		LL cmd = RD();
		if(cmd == 1)change_root();
		else if(cmd == 2)uprange();
		else get_sum();
		}
	return 0;
	}


#include<iostream>
#include<memory.h>
#include<cstdio>
#include<cmath>
#include<queue>
#include<algorithm>
#include<stack>
#include<cstring>
#include<vector>
#include<list>
#include<set>
using namespace std;

const long long N = 100005;

struct Tree
{
    long long l,r,key,tag;
}t[N<<2];

long long dep[N],size[N],fat[N],id[N],son[N],top[N];
//size[v]表示以v为根的子树的节点数
//dep[v]表示v的深度(根深度为1)
//top[v]表示v所在的重链的顶端节点
//fat[v]表示v的父亲
//son[v]表示与v在同一重链上的v的儿子节点（姑且称为重儿子）
//id[v]表示v与其父亲节点的连边（姑且称为v的父边）在线段树中的位置
long long cnt,n,m,root,mod;
long long rid[N],val[N],dp[N][20];
vector <long long> v[N];

void dfs1(long long now,long long fa)
{
    fat[now] = fa;
    dp[now][0] = fa;
    dep[now] = dep[fat[now]] +1;
    size[now] = 1;
    for(long long i = 0; i < v[now].size(); ++i)
    {
        long long u = v[now][i];
        if(u != fa)
        {
            dfs1(u,now);
            size[now] += size[u];
            if(size[u] > size[son[now]])
                son[now] = u;
        }
    }
}

void dfs2(long long now,long long first)
{
    top[now] = first;
    id[now] = ++cnt;
    rid[id[now]] = now;
    if(!son[now]) return;
    dfs2(son[now],first);
    for( long long i = 0; i <v[now].size(); ++i)
    {
        long long u = v[now][i];
        if(u != son[now] && u != fat[now])
            dfs2(u,u);
    }
}

void PushUp(long long now)
{
    t[now].key = t[now << 1].key + t[now << 1 | 1].key;
}

void PushDown(long long now)
{
    t[now<<1].tag += t[now].tag;
    t[now<<1].key += t[now].tag*(t[now<<1].r-t[now<<1].l+1);
    t[now<<1|1].tag += t[now].tag;
    t[now<<1|1].key += t[now].tag*(t[now<<1|1].r-t[now<<1|1].l+1);
    t[now].tag = 0;
}

void Build(long long now,long long l,long long r)
{
    t[now].l = l;
    t[now].r = r;
    if(l == r)
    {
        t[now].key = val[rid[l]];
        return;
    }
    long long mid = (l + r) >> 1;
    Build(now << 1,l,mid);
    Build(now << 1 | 1,mid + 1,r);
    PushUp(now);
}

void Update(long long now,long long l,long long r,long long z)
{
    if(l <= t[now].l && t[now].r <= r)
    {
        t[now].tag += z;
        t[now].key += z * (t[now].r - t[now].l + 1);
        return;
    }
    PushDown(now);
    long long mid = (t[now].l + t[now].r) >> 1;
    if(r <= mid) Update(now << 1,l,r,z);
    else if(l > mid) Update(now << 1 | 1,l,r,z);
    else
    {
        Update(now << 1,l,mid,z);
        Update(now << 1 | 1,mid+1,r,z);
    }
    PushUp(now);
}

long long Query(long long now,long long l,long long r)
{
    if(l <= t[now].l && t[now].r <= r)
        return t[now].key;
    PushDown(now);
    long long mid = (t[now].l + t[now].r) >> 1;
    if(r <= mid) return Query(now << 1,l,r);
    else if(l > mid) return Query(now << 1 | 1,l,r);
    else
        return Query(now << 1,l,mid)+Query(now << 1 | 1,mid+1,r);
}

long long lca(long long x,long long y)
{
    if(dep[x] < dep[y]) swap(x,y);
    for( long long i = 18; i >= 0; --i)
        if(dep[dp[x][i]] >= dep[y])
            x = dp[x][i];
    if(x == y) return x;
    for( long long i = 18; i >= 0; --i)
        if(dp[x][i] != dp[y][i])
        {
            x = dp[x][i];
            y = dp[y][i];
        }
    return dp[x][0];
}

long long Get_Lca(long long x,long long y)
{
    long long t = root;
    long long lca1 = lca(t,x);
    long long lca2 = lca(t,y);
    long long lca3 = lca(x,y);
    if(dep[lca1] >= max(dep[lca2],dep[lca3])) return lca1;//x在上面
    if(dep[lca2] >= max(dep[lca1],dep[lca3])) return lca2;//y在上面
    if(dep[lca3] >= max(dep[lca2],dep[lca1])) return lca3;//root在上面
}

void S_Update(long long x,long long y,long long z)
{
    long long t = Get_Lca(x,y);
    if(t == root)
    {
        Update(1,1,cnt,z);
        return;
    }
    long long tt = root;
    for(long long i = 18; i >= 0; --i)
        if(dep[dp[tt][i]] > dep[t])
            tt = dp[tt][i];
    if(dp[tt][0] != t) Update(1,id[t],id[t]+size[t]-1,z);//tt在t上面
    else
    {
        Update(1,1,id[tt]-1,z);//t到顶端
        Update(1,id[tt]+size[tt],cnt,z);//tt子树后面的点到结束
    }
}

long long S_Query(long long x)
{
    if(x == root) return Query(1,1,n);
    long long tt = root;
    for(long long i = 18; i >= 0; --i)
        if(dep[dp[tt][i]] > dep[x])
            tt = dp[tt][i];
    if(dp[tt][0] != x)
        return Query(1,id[x],id[x]+size[x]-1);//tt在x上面
    else
    {

        return Query(1,1,id[tt]-1) + Query(1,id[tt]+size[tt],cnt);
    }
}

int main()
{
    scanf("%I64d%I64d",&n,&m);
    for( long long i = 1; i <= n; ++i) scanf("%I64d",&val[i]);
    for( long long i = 1; i < n; ++i)
    {
        long long a,b;
        scanf("%I64d%I64d",&a,&b);
        v[a].push_back(b);
        v[b].push_back(a);
    }
    root = 1;
    dfs1(root,0);
    dfs2(root,root);
    Build(1,1,cnt);
    for( long long j = 1; j <= 18; ++j)
        for( long long i = 1; i <= cnt; ++i)
            dp[i][j] = dp[dp[i][j-1]][j-1];
    for( long long i = 0; i < m; ++i)
    {
        long long t,x,y,z;
        scanf("%I64d",&t);
        if(t == 1)
        {
            scanf("%I64d",&x);
            root = x;
        }
        else if(t == 2)
        {
            scanf("%I64d%I64d%I64d",&x,&y,&z);
            S_Update(x,y,z);
        }
        else
        {
            scanf("%I64d",&x);
            printf("%I64d\n",S_Query(x));
        }
    }
    return 0;
}