#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
int read()
{
	char ch=getchar();int f=0,x=1;
	while(ch<'0'||ch>'9'){if(ch=='-') x=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){f=(f<<1)+(f<<3)+ch-'0';ch=getchar();}
	return f*x;
}
struct segtree
{
	int ls;
	int rs;
	ll sum;
	int mark;
}tree[400005];
struct node
{
	int from;
	int to;
	int next;
}edge[200005];
int tot=1,pos[100005],npos[100005],size[100005];
int cnt,n,head[200005],m,rt,tar,fa[200005],a[200005];
int anc[200005][25];bool vis[200005];
int dep[200005];
void add(int u,int v)
{
	edge[cnt].from=u;
	edge[cnt].to=v;
	edge[cnt].next=head[u];
	head[u]=cnt++;
}
void build(int p,int l,int r)
{
	int mid=l+r>>1;
	if(l==r)
	{
		tree[p].sum=a[npos[mid]];
		return;
	}
	tree[p].ls=++tot;
	tree[p].rs=++tot;
	build(tree[p].ls,l,mid);
	build(tree[p].rs,mid+1,r);
	tree[p].sum=tree[tree[p].ls].sum+tree[tree[p].rs].sum;
}
void dfs(int x)
{
	size[x]=1;
	pos[x]=++tar;
	npos[tar]=x;
	for(int i=head[x];i!=-1;i=edge[i].next)
	{
		if(fa[x]!=edge[i].to)
		{
			fa[edge[i].to]=x;
			dfs(edge[i].to);
			size[x]+=size[edge[i].to];
		}
	}
}
void dfs2(int x)
{
    vis[x]=1;
    for(int i=1;i<=20;i++)
    {
        if(dep[x]<=(1<<i))
        break;
        anc[x][i]=anc[anc[x][i-1]][i-1];
    }
    for(int i=head[x];i!=-1;i=edge[i].next)
    {
        if(!anc[edge[i].to][0]&&edge[i].to!=rt)
        {
            dep[edge[i].to]=dep[x]+1;
            anc[edge[i].to][0]=x;
            dfs2(edge[i].to);
        }
    }
}
int lca(int x,int y)
{
	//cout<<x<<" "<<y<<endl;
    if(dep[x]<dep[y]) swap(x,y);
    for(int i=20;i>=0;i--)
    {
        if(dep[y]<=dep[anc[x][i]])
        {
        	//cout<<dep[y]<<" "<<dep[x]<<" "<<y<<" "<<x<<endl;
        	x=anc[x][i];
        	//cout<<x<<" ";
		}

    }
    if(x==y) return x;
    //cout<<x<<" "<<y<<endl;
    for(int i=20;i>=0;i--)
    {
        if(anc[x][i]!=anc[y][i])
        {
            x=anc[x][i];
            y=anc[y][i];
        }
    }
    //cout<<"lca"<<x<<" "<<y<<endl;
    if(x==y) return x;
    if(!anc[x][0]) return 1;
    return anc[x][0];
}
ll query(int p,int l,int r,int x,int y)
{
	//cout<<l<<" "<<r<<" "<<x<<" "<<y<<endl;
	int mid=l+r>>1;
	if(l==x&&r==y) return tree[p].sum;
	if(y<=mid) return query(tree[p].ls,l,mid,x,y);
	else if(x>mid) return query(tree[p].rs,mid+1,r,x,y);
	else
	{
		return query(tree[p].ls,l,mid,x,mid)+query(tree[p].rs,mid+1,r,mid+1,y);
	}
}
void modify(int p,int l,int r,int x,int y,int z)
{
	int mid=l+r>>1;
	if(l==x&&r==y)
	{
		tree[p].sum+=1LL*(r-l+1)*z;
		tree[p].mark+=z;
		return;
	}
	if(tree[p].mark)
	{
		tree[tree[p].ls].mark+=tree[p].mark;
		tree[tree[p].rs].mark+=tree[p].mark;
		tree[tree[p].ls].sum+=1LL*(mid-l+1)*tree[p].mark;
		tree[tree[p].rs].sum+=1LL*(r-mid)*tree[p].mark;
		tree[p].mark=0;
	}
	if(y<=mid) modify(tree[p].ls,l,mid,x,y,z);
	else if(x>mid) modify(tree[p].rs,mid+1,r,x,y,z);
	else
	{
		modify(tree[p].ls,l,mid,x,mid,z);
		modify(tree[p].rs,mid+1,r,mid+1,y,z);
	}
	tree[p].sum=tree[tree[p].ls].sum+tree[tree[p].rs].sum;
}
int main()
{
	memset(head,-1,sizeof(head));
	n=read();m=read();
	for(int i=1;i<=n;i++) a[i]=read();
	for(int i=1;i<n;i++)
	{
		int u=read(),v=read();
		add(u,v);
		add(v,u);
	}
	dep[1]=1;rt=1;
	dfs(1);
	dfs2(1);

	build(1,1,n);
	//for(int i=1;i<=n;i++) cout<<pos[i]<<" ";
	//cout<<endl;
	//cout<<tree[1].sum<<endl;
	for(int i=1;i<=m;i++)
	{
		int op=read();
		if(op==1)
		{
			rt=read();
		}
		else if(op==2)
		{
			int x=read(),y=read(),z=read();
			x=lca(x,y)^lca(x,rt)^lca(y,rt);
			//cout<<lca(x,y)<<" "<<lca(x,rt)<<" "<<lca(y,rt)<<endl;
			//cout<<x<<endl;
			if(x==rt) modify(1,1,n,1,n,z);
			else if(lca(x,rt)==x)
			{
				modify(1,1,n,1,n,z);
				modify(1,1,n,pos[x],pos[x]+size[x]-1,-z);
				modify(1,1,n,pos[x],pos[x],z);
			}
			else
			{

				modify(1,1,n,pos[x],pos[x]+size[x]-1,z);
			}
		}
		else if(op==3)

		{
			int x=read();
			//cout<<x<<" "<<rt<<" "<<lca(x,rt)<<endl;
			if(x==rt) printf("%lld\n",tree[1].sum);
			else if(lca(x,rt)==x)
			{
				//cout<<x<<endl;
				printf("%lld\n",tree[1].sum-query(1,1,n,pos[x],pos[x]+size[x]-1)+query(1,1,n,pos[x],pos[x]));
			}
			else
			{
				//cout<<pos[x]<<" "<<size[x]<<endl;;
				printf("%lld\n",query(1,1,n,pos[x],pos[x]+size[x]-1));
			}
		}
	}
}


#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
int read()
{
	char ch=getchar();int f=0,x=1;
	while(ch<'0'||ch>'9'){if(ch=='-') x=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){f=(f<<1)+(f<<3)+ch-'0';ch=getchar();}
	return f*x;
}
struct segtree
{
	int ls;
	int rs;
	ll sum;
	ll mark;
}tree[400005];
struct node
{
	int from;
	int to;
	int next;
}edge[200005];
int tot=1,pos[100005],npos[100005],size[100005];
int cnt,n,head[200005],m,rt,tar,fa[200005],a[200005];
int anc[200005][25];bool vis[200005];
int dep[200005];
void add(int u,int v)
{
	edge[cnt].from=u;
	edge[cnt].to=v;
	edge[cnt].next=head[u];
	head[u]=cnt++;
}
void build(int p,int l,int r)
{
	int mid=l+r>>1;
	if(l==r)
	{
		tree[p].sum=a[npos[mid]];
		return;
	}
	tree[p].ls=++tot;
	tree[p].rs=++tot;
	build(tree[p].ls,l,mid);
	build(tree[p].rs,mid+1,r);
	tree[p].sum=tree[tree[p].ls].sum+tree[tree[p].rs].sum;
}
void dfs(int x)
{
	size[x]=1;
	pos[x]=++tar;
	npos[tar]=x;
	for(int i=head[x];i!=-1;i=edge[i].next)
	{
		if(fa[x]!=edge[i].to)
		{
			fa[edge[i].to]=x;
			dfs(edge[i].to);
			size[x]+=size[edge[i].to];
		}
	}
}
void dfs2(int x)
{
    vis[x]=1;
    for(int i=1;i<=20;i++)
    {
        if(dep[x]<=(1<<i))
        break;
        anc[x][i]=anc[anc[x][i-1]][i-1];
    }
    for(int i=head[x];i!=-1;i=edge[i].next)
    {
        if(!anc[edge[i].to][0]&&edge[i].to!=rt)
        {
            dep[edge[i].to]=dep[x]+1;
            anc[edge[i].to][0]=x;
            dfs2(edge[i].to);
        }
    }
}
int lca(int x,int y)
{
	//cout<<x<<" "<<y<<endl;
    if(dep[x]<dep[y]) swap(x,y);
    for(int i=20;i>=0;i--)
    {
        if(dep[y]<=dep[anc[x][i]])
        {
        	//cout<<dep[y]<<" "<<dep[x]<<" "<<y<<" "<<x<<endl;
        	x=anc[x][i];
        	//cout<<x<<" ";
		}

    }
    if(x==y) return x;
    //cout<<x<<" "<<y<<endl;
    for(int i=20;i>=0;i--)
    {
        if(anc[x][i]!=anc[y][i])
        {
            x=anc[x][i];
            y=anc[y][i];
        }
    }
    //cout<<"lca"<<x<<" "<<y<<endl;
    if(x==y) return x;
    if(!anc[x][0]) return 1;
    return anc[x][0];
}
ll query(int p,int l,int r,int x,int y)
{
	//cout<<l<<" "<<r<<" "<<x<<" "<<y<<endl;
	int mid=l+r>>1;
	if(l==x&&r==y) return tree[p].sum;
	if(tree[p].mark)
	{
		tree[tree[p].ls].mark+=tree[p].mark;
		tree[tree[p].rs].mark+=tree[p].mark;
		tree[tree[p].ls].sum+=1LL*(mid-l+1)*tree[p].mark;
		tree[tree[p].rs].sum+=1LL*(r-mid)*tree[p].mark;
		tree[p].mark=0;
	}
	if(y<=mid) return query(tree[p].ls,l,mid,x,y);
	else if(x>mid) return query(tree[p].rs,mid+1,r,x,y);
	else
	{
		return query(tree[p].ls,l,mid,x,mid)+query(tree[p].rs,mid+1,r,mid+1,y);
	}
}
void modify(int p,int l,int r,int x,int y,int z)
{
	int mid=l+r>>1;
	if(l==x&&r==y)
	{
		tree[p].sum+=1LL*(r-l+1)*z;
		tree[p].mark+=z;
		return;
	}
	if(tree[p].mark)
	{
		tree[tree[p].ls].mark+=tree[p].mark;
		tree[tree[p].rs].mark+=tree[p].mark;
		tree[tree[p].ls].sum+=1LL*(mid-l+1)*tree[p].mark;
		tree[tree[p].rs].sum+=1LL*(r-mid)*tree[p].mark;
		tree[p].mark=0;
	}
	if(y<=mid) modify(tree[p].ls,l,mid,x,y,z);
	else if(x>mid) modify(tree[p].rs,mid+1,r,x,y,z);
	else
	{
		modify(tree[p].ls,l,mid,x,mid,z);
		modify(tree[p].rs,mid+1,r,mid+1,y,z);
	}
	tree[p].sum=tree[tree[p].ls].sum+tree[tree[p].rs].sum;
}
int getp(int x)
{
	int now=rt;
	for(int i=20;i>=0;i--)
	{

		if(dep[anc[now][i]]>=dep[x]+1)
		{
			now=anc[now][i];
		}
	}
	return now;
}
int main()
{
	memset(head,-1,sizeof(head));
	n=read();m=read();
	for(int i=1;i<=n;i++) a[i]=read();
	for(int i=1;i<n;i++)
	{
		int u=read(),v=read();
		add(u,v);
		add(v,u);
	}
	dep[1]=1;rt=1;
	dfs(1);
	dfs2(1);

	build(1,1,n);
	//for(int i=1;i<=n;i++) cout<<pos[i]<<" ";
	//cout<<endl;
	//cout<<tree[1].sum<<endl;
	for(int i=1;i<=m;i++)
	{//for(int j=1;j<=n;j++)
				//cout<<query(1,1,n,pos[j],pos[j])<<" ";
		int op=read();
		if(op==1)
		{
			rt=read();
		}
		else if(op==2)
		{
			int x=read(),y=read(),z=read();
			x=lca(x,y)^lca(x,rt)^lca(y,rt);
			//cout<<lca(x,y)<<" "<<lca(x,rt)<<" "<<lca(y,rt)<<endl;
			//cout<<x<<endl;
			if(x==rt) modify(1,1,n,1,n,z);
			else if(lca(x,rt)==x)
			{
				modify(1,1,n,1,n,z);

				int now=getp(x);
				modify(1,1,n,pos[now],pos[now]+size[now]-1,-z);
				//cout<<pos[x]<<" "<<size[x]<<endl;
			}
			else
			{
				//cout<<"ok"<<" "<<size[x]<<" ";
				modify(1,1,n,pos[x],pos[x]+size[x]-1,z);
			}
		}
		else if(op==3)

		{
			int x=read();
			//cout<<x<<" "<<rt<<" "<<lca(x,rt)<<endl;
			if(x==rt) printf("%lld\n",tree[1].sum);
			else if(lca(x,rt)==x)
			{
				//cout<<x<<" "<<rt<<endl;
				//cout<<tree[1].sum<<" ";

				//cout<<endl;
				int now=getp(x);
				//cout<<now<<" ";
				printf("%lld\n",tree[1].sum-query(1,1,n,pos[now],pos[now]+size[now]-1));
			}
			else
			{
				//cout<<pos[x]<<" "<<size[x]<<endl;;
				printf("%lld\n",query(1,1,n,pos[x],pos[x]+size[x]-1));
			}
		}
	}
}


#include <cstdio>
#include <iostream>
#include <vector>
#define  MAXN 100010
using namespace std;
typedef long long ll;

int order;
int N, Q;
int rev_ord[MAXN], ord[MAXN];
int depth[MAXN], dn[MAXN], anc[MAXN][20];
ll ar[MAXN], KD[MAXN*4], lazy[MAXN*4];
vector<int> edge[MAXN];
int root, start, finish;

void dfs(int n, int prev) {

	ord[n] = order;
	rev_ord[order] = n;
	order++;

	dn[n] = 1;
	anc[n][0] = prev;

	for(int i=0; i < (int)edge[n].size(); i++)
		if(edge[n][i] != prev) {

			depth[edge[n][i]] = depth[n] + 1;
			dfs(edge[n][i], n);
			dn[n] += dn[edge[n][i]];
		}

}

void init(int l, int r, int n) {

	if(l == r) {

		KD[n] = ar[rev_ord[l]];
		return;
	}

	init(l, (l+r)/2, 2*n+1);
	init((l+r)/2+1, r, 2*n+2);

	KD[n] = KD[2*n+1] + KD[2*n+2];
}

void update(int l, int r, int s, int e, int n, ll val) {

	if(lazy[n]) {

		KD[n] += lazy[n]*(r-l+1);

		if(l!=r){

			lazy[2*n+1] += lazy[n];
			lazy[2*n+2] += lazy[n];
		}

		lazy[n] = 0;
	}

	if(s > r || e < l)
		return;

	if(s <= l && e >= r) {

		KD[n] += val*(r-l+1);

		if(l!=r) {

			lazy[2*n+1] += val;
			lazy[2*n+2] += val;
		}

		return;
	}

	update(l, (l+r)/2, s, e, 2*n+1, val);
	update((l+r)/2+1, r, s, e, 2*n+2, val);

	KD[n] = KD[2*n+1] + KD[2*n+2];
}

ll find(int l, int r, int s, int e, int n) {

	if(lazy[n]) {

		KD[n] += lazy[n]*(r-l+1);

		if(l!=r){

			lazy[2*n+1] += lazy[n];
			lazy[2*n+2] += lazy[n];
		}

		lazy[n] = 0;
	}

	if(s > r || e < l)
		return 0;

	if(s <= l && e >= r)
		return KD[n];

	return find(l, (l+r)/2, s, e, 2*n+1) + find((l+r)/2+1, r, s, e, 2*n+2);
}

int LCA(int u, int v) {

	if(depth[u] < depth[v])
		swap(u,v);

	int diff = depth[u] - depth[v];

	for(int i=16; i>=0; i--)
		if((1<<i) & diff)
			u = anc[u][i];

	if(u == v)
		return u;

	for(int i=16; i>=0; i--)
		if(anc[u][i] != anc[v][i]) {

			u = anc[u][i];
			v = anc[v][i];
		}

	return anc[u][0];
}

int main() {

	int a, b, q;

	cin >> N >> Q;

	root = 1;
	start = 0;
	finish = N-1;

	for(int i=1; i<=N; i++)
		cin >> ar[i];

	for(int i=1; i<N; i++)
	{
		cin >> a >> b;
		edge[a].push_back(b);
		edge[b].push_back(a);
	}

	dfs(1, 0);

	init(0, N-1, 0);

	for(int j=1; j<=16; j++)
		for(int i=1; i<=N; i++)
			anc[i][j] = anc[anc[i][j-1]][j-1];

	for(int i=0; i<Q; i++) {

		cin >> q;

		if(q == 1) {

			cin >> root;
			start = ord[root];
			finish = ord[root] + dn[root] - 1;
		}

		else if(q == 2) {

			int u, v;
			ll c;
			cin >> u >> v >> c;

			int lca;
			bool flag1 = start <= ord[u] && ord[u] <= finish;
			bool flag2 = start <= ord[v] && ord[v] <= finish;

			//cout << flag1 << " " << flag2 << endl;
			if(flag1 && flag2)
				lca = LCA(u, v);

			else if(flag1 || flag2)
				lca = root;

			else {

				int c1 = LCA(u, root);
				int c2 = LCA(v, root);
				int c3 = LCA(u, v);
				//cout << c1 << "  " << c2 << " " << c3 << endl;

				if(depth[c1] >= depth[c2] && depth[c1] >= depth[c3])
					lca = c1;
				else if(depth[c2] >= depth[c3])
					lca = c2;
				else
					lca = c3;
			}

			//cout << "case 2: ROOT OF SUBTREE is " << lca << endl;

			if(lca == root)
				update(0, N-1, 0, N-1, 0, c);

			else if(start < ord[lca] && ord[lca] <= finish) {
			//	cout << "case 2-2: update araligi " << ord[lca] << " " << ord[lca] + dn[lca] - 1 << endl;
				update(0, N-1, ord[lca], ord[lca] + dn[lca] - 1, 0, c);
			}

			else if(ord[lca] < ord[root] && ord[root] <= ord[lca] + dn[lca] - 1)
			{

				update(0, N-1, 0, N-1, 0, c);

				int diff = depth[root] - depth[lca] - 1;
				int undo = root;

				//cout << diff << endl;

				for(int j = 16; j >= 0 ; j--)
					if(diff & (1<<j))
						undo = anc[undo][j];

				update(0, N-1, ord[undo], ord[undo] + dn[undo] - 1, 0, -c);

				//cout << "case 2-3: update araligi her yer eksi " << ord[undo] << " " << ord[undo] + dn[undo] - 1 << endl;

			}

			else
				update(0, N-1, ord[lca], ord[lca] + dn[lca] - 1, 0, c);

		}

		else {

			int lca;
			cin >> lca;

			ll ans;

			if(lca == root)
				ans = find(0, N-1, 0, N-1, 0);

			else if(start < ord[lca] && ord[lca] <= finish)
				ans = find(0, N-1, ord[lca], ord[lca] + dn[lca] - 1, 0);

			else if(ord[lca] < ord[root] && ord[root] <= ord[lca] + dn[lca] - 1)
			{
				ans = find(0, N-1, 0, N-1, 0);

				int diff = depth[root] - depth[lca] - 1;
				int undo = root;

				for(int j = 16; j >= 0 ; j--)
					if(diff & (1<<j))
						undo = anc[undo][j];

				ans -= find(0, N-1, ord[undo], ord[undo] + dn[undo] - 1, 0);
			}

			else
				ans = find(0, N-1, ord[lca], ord[lca] + dn[lca] - 1, 0);

			cout << ans << endl;
		}

		//cout << "operation " << i+1 << ":  ";
		//for(int j=1;j<=N;j++)
		//	cout << find(0, N-1, ord[j], ord[j], 0) << " ";
		//cout << endl;
	}

	return 0;
}


#include <cstdio>
#include <iostream>
#include <vector>
#define  MAXN 100010
using namespace std;
typedef long long ll;

int order;
int N, Q;
int rev_ord[MAXN], ord[MAXN], subtree[MAXN];
int depth[MAXN], dn[MAXN], anc[MAXN][20];
ll ar[MAXN], KD[MAXN*4], lazy[MAXN*4];
vector<int> edge[MAXN];
int root, start, finish;

void dfs(int n, int prev) {

	ord[n] = order;
	rev_ord[order] = n;
	order++;

	dn[n] = 1;
	anc[n][0] = prev;

	for(int i=0; i < (int)edge[n].size(); i++)
		if(edge[n][i] != prev) {

			depth[edge[n][i]] = depth[n] + 1;
			dfs(edge[n][i], n);
			dn[n] += dn[edge[n][i]];
		}

}

void init(int l, int r, int n) {

	if(l == r) {

		KD[n] = ar[rev_ord[l]];
		return;
	}

	init(l, (l+r)/2, 2*n+1);
	init((l+r)/2+1, r, 2*n+2);

	KD[n] = KD[2*n+1] + KD[2*n+2];
}

void update(int l, int r, int s, int e, int n, ll val) {

	if(lazy[n]) {

		KD[n] += lazy[n]*(r-l+1);

		if(l!=r){

			lazy[2*n+1] += lazy[n];
			lazy[2*n+2] += lazy[n];
		}

		lazy[n] = 0;
	}

	if(s > r || e < l)
		return;

	if(s <= l && e >= r) {

		KD[n] += val*(r-l+1);

		if(l!=r) {

			lazy[2*n+1] += val;
			lazy[2*n+2] += val;
		}

		return;
	}

	update(l, (l+r)/2, s, e, 2*n+1, val);
	update((l+r)/2+1, r, s, e, 2*n+2, val);

	KD[n] = KD[2*n+1] + KD[2*n+2];
}

int find(int l, int r, int s, int e, int n) {

	if(lazy[n]) {

		KD[n] += lazy[n]*(r-l+1);

		if(l!=r){

			lazy[2*n+1] += lazy[n];
			lazy[2*n+2] += lazy[n];
		}

		lazy[n] = 0;
	}

	if(s > r || e < l)
		return 0;

	if(s <= l && e >= r)
		return KD[n];

	return find(l, (l+r)/2, s, e, 2*n+1) + find((l+r)/2+1, r, s, e, 2*n+2);
}

int LCA(int u, int v) {

	if(depth[u] < depth[v])
		swap(u,v);

	int diff = depth[u] - depth[v];

	for(int i=16; i>=0; i--)
		if((1<<i) & diff)
			u = anc[u][i];

	if(u == v)
		return u;

	for(int i=16; i>=0; i--)
		if(anc[u][i] != anc[v][i]) {

			u = anc[u][i];
			v = anc[v][i];
		}

	return anc[u][0];
}

int main() {

	int a, b, q;

	cin >> N >> Q;

	root = 1;
	start = 0;
	finish = N-1;

	for(int i=1; i<=N; i++)
		cin >> ar[i];

	for(int i=1; i<N; i++)
	{
		cin >> a >> b;
		edge[a].push_back(b);
		edge[b].push_back(a);
	}

	dfs(1, 0);

	init(0, N-1, 0);

	for(int j=1; j<=16; j++)
		for(int i=1; i<=N; i++)
			anc[i][j] = anc[anc[i][j-1]][j-1];

	for(int i=0; i<Q; i++) {

		cin >> q;

		if(q == 1) {

			cin >> root;
			start = ord[root];
			finish = ord[root] + dn[root] - 1;
		}

		else if(q == 2) {

			int u, v;
			ll c;
			cin >> u >> v >> c;

			int lca;
			bool flag1 = start <= ord[u] && ord[u] <= finish;
			bool flag2 = start <= ord[v] && ord[v] <= finish;

			//cout << flag1 << " " << flag2 << endl;
			if(flag1 && flag2)
				lca = LCA(u, v);

			else if(flag1 || flag2)
				lca = root;

			else {

				int c1 = LCA(u, root);
				int c2 = LCA(v, root);
				int c3 = LCA(u, v);
				//cout << c1 << "  " << c2 << " " << c3 << endl;

				if(depth[c1] >= depth[c2] && depth[c1] >= depth[c3])
					lca = c1;
				else if(depth[c2] >= depth[c3])
					lca = c2;
				else
					lca = c3;
			}

			//cout << "case 2: ROOT OF SUBTREE is " << lca << endl;

			if(lca == root)
				update(0, N-1, 0, N-1, 0, c);

			else if(start < ord[lca] && ord[lca] <= finish) {
			//	cout << "case 2-2: update araligi " << ord[lca] << " " << ord[lca] + dn[lca] - 1 << endl;
				update(0, N-1, ord[lca], ord[lca] + dn[lca] - 1, 0, c);
			}

			else if(ord[lca] < ord[root] && ord[root] <= ord[lca] + dn[lca] - 1)
			{

				update(0, N-1, 0, N-1, 0, c);

				int diff = depth[root] - depth[lca] - 1;
				int undo = root;

				//cout << diff << endl;

				for(int j = 16; j >= 0 ; j--)
					if(diff & (1<<j))
						undo = anc[undo][j];

				update(0, N-1, ord[undo], ord[undo] + dn[undo] - 1, 0, -c);

				//cout << "case 2-3: update araligi her yer eksi " << ord[undo] << " " << ord[undo] + dn[undo] - 1 << endl;

			}

			else
				update(0, N-1, ord[lca], ord[lca] + dn[lca] - 1, 0, c);

		}

		else {

			int lca;
			cin >> lca;

			ll ans;

			if(lca == root)
				ans = find(0, N-1, 0, N-1, 0);

			else if(start < ord[lca] && ord[lca] <= finish)
				ans = find(0, N-1, ord[lca], ord[lca] + dn[lca] - 1, 0);

			else if(ord[lca] < ord[root] && ord[root] <= ord[lca] + dn[lca] - 1)
			{
				ans = find(0, N-1, 0, N-1, 0);

				int diff = depth[root] - depth[lca] - 1;
				int undo = root;

				for(int j = 16; j >= 0 ; j--)
					if(diff & (1<<j))
						undo = anc[undo][j];

				ans -= find(0, N-1, ord[undo], ord[undo] + dn[undo] - 1, 0);
			}

			else
				ans = find(0, N-1, ord[lca], ord[lca] + dn[lca] - 1, 0);

			cout << ans << endl;
		}

		//cout << "operation " << i+1 << ":  ";
		//for(int j=1;j<=N;j++)
		//	cout << find(0, N-1, ord[j], ord[j], 0) << " ";
		//cout << endl;
	}

	return 0;
}


#include <cstdio>
#include <iostream>
#include <vector>
#define  MAXN 100010
using namespace std;
typedef long long ll;

int order;
int N, Q;
int rev_ord[MAXN], ord[MAXN], subtree[MAXN];
int depth[MAXN], dn[MAXN], anc[MAXN][20];
ll ar[MAXN], KD[MAXN*4], lazy[MAXN*4];
vector<int> edge[MAXN];
int root, start, finish;

void dfs(int n, int prev) {

	ord[n] = order;
	rev_ord[order] = n;
	order++;

	dn[n] = 1;
	anc[n][0] = prev;

	for(int i=0; i < (int)edge[n].size(); i++)
		if(edge[n][i] != prev) {

			depth[edge[n][i]] = depth[n] + 1;
			dfs(edge[n][i], n);
			dn[n] += dn[edge[n][i]];
		}

}

void init(int l, int r, int n) {

	if(l == r) {

		KD[n] = ar[rev_ord[l]];
		return;
	}

	init(l, (l+r)/2, 2*n+1);
	init((l+r)/2+1, r, 2*n+2);

	KD[n] = KD[2*n+1] + KD[2*n+2];
}

void update(int l, int r, int s, int e, int n, ll val) {

	if(lazy[n]) {

		KD[n] += lazy[n]*(r-l+1);

		if(l!=r){

			lazy[2*n+1] += lazy[n];
			lazy[2*n+2] += lazy[n];
		}

		lazy[n] = 0;
	}

	if(s > r || e < l)
		return;

	if(s <= l && e >= r) {

		KD[n] += val*(r-l+1);

		if(l!=r) {

			lazy[2*n+1] += val;
			lazy[2*n+2] += val;
		}

		return;
	}

	update(l, (l+r)/2, s, e, 2*n+1, val);
	update((l+r)/2+1, r, s, e, 2*n+2, val);

	KD[n] = KD[2*n+1] + KD[2*n+2];
}

int find(int l, int r, int s, int e, int n) {

	if(lazy[n]) {

		KD[n] += lazy[n]*(r-l+1);

		if(l!=r){

			lazy[2*n+1] += lazy[n];
			lazy[2*n+2] += lazy[n];
		}

		lazy[n] = 0;
	}

	if(s > r || e < l)
		return 0;

	if(s <= l && e >= r)
		return KD[n];

	return find(l, (l+r)/2, s, e, 2*n+1) + find((l+r)/2+1, r, s, e, 2*n+2);
}

int LCA(int u, int v) {

	if(depth[u] < depth[v])
		swap(u,v);

	int diff = depth[u] - depth[v];

	for(int i=16; i>=0; i--)
		if((1<<i) & diff)
			u = anc[u][i];

	if(u == v)
		return u;

	for(int i=16; i>=0; i--)
		if(anc[u][i] != anc[v][i]) {

			u = anc[u][i];
			v = anc[v][i];
		}

	return anc[u][0];
}

int main() {

	int a, b, q;

	cin >> N >> Q;

	root = 1;
	start = 0;
	finish = N-1;

	for(int i=1; i<=N; i++)
		cin >> ar[i];

	for(int i=1; i<N; i++)
	{
		cin >> a >> b;
		edge[a].push_back(b);
		edge[b].push_back(a);
	}

	dfs(1, 0);

	init(0, N-1, 0);

	for(int j=1; j<=16; j++)
		for(int i=1; i<=N; i++)
			anc[i][j] = anc[anc[i][j-1]][j-1];

	for(int i=0; i<Q; i++) {

		cin >> q;

		if(q == 1) {

			cin >> root;
			start = ord[root];
			finish = ord[root] + dn[root] - 1;
		}

		else if(q == 2) {

			int u, v;
			ll c;
			cin >> u >> v >> c;

			int lca;
			bool flag1 = start <= ord[u] && ord[u] <= finish;
			bool flag2 = start <= ord[v] && ord[v] <= finish;

			//cout << flag1 << " " << flag2 << endl;
			if(flag1 && flag2)
				lca = LCA(u, v);

			else if(flag1 || flag2)
				lca = root;

			else {

				int c1 = LCA(u, root);
				int c2 = LCA(v, root);
				int c3 = LCA(u, v);
				//cout << c1 << "  " << c2 << " " << c3 << endl;

				if(depth[c1] >= depth[c2] && depth[c1] >= depth[c3])
					lca = c1;
				else if(depth[c2] >= depth[c3])
					lca = c2;
				else
					lca = c3;
			}

			//cout << "case 2: ROOT OF SUBTREE is " << lca << endl;

			if(lca == root)
				update(0, N-1, 0, N-1, 0, c);

			else if(start < ord[lca] && ord[lca] <= finish) {
			//	cout << "case 2-2: update araligi " << ord[lca] << " " << ord[lca] + dn[lca] - 1 << endl;
				update(0, N-1, ord[lca], ord[lca] + dn[lca] - 1, 0, c);
			}

			else if(ord[lca] < ord[root] && ord[root] <= ord[lca] + dn[lca] - 1)
			{

				update(0, N-1, 0, N-1, 0, c);

				int diff = depth[root] - depth[lca] - 1;
				int undo = root;

				//cout << diff << endl;

				for(int j = 16; j >= 0 ; j--)
					if(diff & (1<<j))
						undo = anc[undo][j];

				update(0, N-1, ord[undo], ord[undo] + dn[undo] - 1, 0, -c);

				//cout << "case 2-3: update araligi her yer eksi " << ord[undo] << " " << ord[undo] + dn[undo] - 1 << endl;

			}

			else
				update(0, N-1, ord[lca], ord[lca] + dn[lca] - 1, 0, c);

		}

		else {

			int lca;
			cin >> lca;

			ll ans;

			if(lca == root)
				ans = find(0, N-1, 0, N-1, 0);

			else if(start < ord[lca] && ord[lca] <= finish)
				ans = find(0, N-1, ord[lca], ord[lca] + dn[lca] - 1, 0);

			else if(ord[lca] < ord[root] && ord[root] <= ord[lca] + dn[lca] - 1)
			{
				ans = find(0, N-1, 0, N-1, 0);

				int diff = ord[root] - ord[lca] - 1;
				int undo = root;

				for(int j = 16; j >= 0 ; j--)
					if(diff & (1<<j))
						undo = anc[undo][j];

				ans -= find(0, N-1, ord[undo], ord[undo] + dn[undo] - 1, 0);
			}

			else
				ans = find(0, N-1, ord[lca], ord[lca] + dn[lca] - 1, 0);

			cout << ans << endl;
		}

		//cout << "operation " << i+1 << ":  ";
		//for(int j=1;j<=N;j++)
		//	cout << find(0, N-1, ord[j], ord[j], 0) << " ";
		//cout << endl;
	}

	return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define mp make_pair
#define vi vector< int >
#define vb vector< bool >
#define vl vector< ll >
#define ss second
#define ff first
#define ll long long
#define pii pair< int,int >
#define pll pair< ll,ll >
#define sz(a) a.size()
#define sort(a) sort(a.begin(),a.end())
#define inf (1000*1000*1000+5)
#define all(a) a.begin(),a.end()
#define tri pair<int,pii>
#define vii vector<pii>
#define vll vector<pll>
#define viii vector<tri>
#define mod (1000*1000*1000+7)
#define moddd (1000*1000*1000+9)
#define pqueue priority_queue< int >
#define pdqueue priority_queue< int,vi ,greater< int > >
#define endl "\n"
#define flush fflush(stdout)
#define pi 3.14159265358979323846264338327950
#define primeDEN 727999983
//cout<<fixed<<setprecision(15)<<ans;

template <typename T>
void printvec(vector<T>& vec){
	for(int i=0;i<vec.size();i++){
		cout<<vec[i]<<" ";
	}
	cout<<endl;
}

#define N 100005
#define H 20

vector<vi> adj;
vi cost;
vi pre,post;
int ctr=0;
vl st,lazy;
int root;
vi level;
int par[N][H];
int n;

void update(int si,int ss,int se,int qs,int qe,ll val){
	//cout<<qs<<" "<<qe<<endl;
	if(lazy[si]!=0){
		ll len=se-ss+1;
		st[si]+=(len*lazy[si]);
		if(ss!=se){
			lazy[2*si]+=lazy[si];
			lazy[2*si+1]+=lazy[si];
		}
		lazy[si]=0;
		//return;
	}
	if(qe<ss||qs>se) return;
	if(qs<=ss&&se<=qe){
		ll len=se-ss+1;
		st[si]+=(len*val);
		if(ss!=se){
			lazy[2*si]+=val;
			lazy[2*si+1]+=val;
		}
		return;
	}
	int mid=(ss+se)/2;
	update(2*si,ss,mid,qs,qe,val);
	update(2*si+1,mid+1,se,qs,qe,val);
	st[si]=st[2*si]+st[2*si+1];
}

ll getsum(int si,int ss,int se,int qs,int qe){
	if(lazy[si]!=0){
		ll len=se-ss+1;
		st[si]+=(len*lazy[si]);
		if(ss!=se){
			lazy[2*si]+=lazy[si];
			lazy[2*si+1]+=lazy[si];
		}
		lazy[si]=0;
	}
	if(qe<ss||qs>se) return 0;
	if(qs<=ss&&se<=qe) return st[si];
	int mid=(ss+se)/2;
	return getsum(2*si,ss,mid,qs,qe)+getsum(2*si+1,mid+1,se,qs,qe);
}

void dfs(int curr,int prev){
	pre[curr]=(ctr++);
	par[curr][0]=prev;
	if(prev==-1) level[curr]=0;
	else level[curr]=level[prev]+1;
	int i;
	for(i=0;i<adj[curr].size();i++){
		if(adj[curr][i]==prev) continue;
		dfs(adj[curr][i],curr);
	}
	post[curr]=ctr-1;
}

int getkthpar(int a,int k){
	int lev=level[a]-k;
	if(lev<0) return -1;
	int i;
	for(i=H-1;i>=0;i--){
		if((level[a]-lev)>=(1<<i)) a=par[a][i];
	}
	return a;
}

int getlca(int a,int b){
	int i;
	if(level[a]<level[b]) swap(a,b);
	int diff=level[a]-level[b];
	a=getkthpar(a,diff);
	if(a==-1) return -1;
	if(a==b) return a;
	for(i=H-1;i>=0;i--){
		if(par[a][i]!=par[b][i]){
			a=par[a][i];
			b=par[b][i];
		}
	}
	return par[a][0];
}

bool ispresent(int a,int b){
	if(pre[a]<=pre[b]&&post[b]<=post[a]) return true;
	return false;
}

void handle2(int u,int v,ll x){
	if(u==root||v==root){
		update(1,0,ctr-1,0,ctr-1,x);
		return;
	}
	int curr=u;
	if(u!=v){
		int diff=level[u]-level[root];
		diff--;
		int a=getkthpar(u,diff);
		int l=getlca(u,v);
		if(ispresent(a,v)&&ispresent(root,v)&&ispresent(root,u)){
			update(1,0,ctr-1,pre[l],post[l],x);
			//cout<<"shit"<<u<<" "<<a<<" "<<l<<endl;
			return;
		}
		if(ispresent(root,v)&&ispresent(root,u)){
			//cout<<"shit"<<endl;
			update(1,0,ctr-1,0,ctr-1,x);
			return;
		}
		if(ispresent(root,u)||ispresent(root,v)){
			update(1,0,ctr-1,0,ctr-1,x);
			return;
		}
		int l1=getlca(u,root);
		int l2=getlca(v,root);
		int l3=getlca(u,v);
		if(level[l1]>level[l2]) l=l1;
		else l=l2;
		if(level[l]<level[l3]) l=l3;
		curr=l;
	}

	//cout<<curr<<endl;
	if(curr==root) update(1,0,ctr-1,0,ctr-1,x);
	else if(ispresent(curr,root)){
		int diff=level[root]-level[curr];
		diff--;
		int a=getkthpar(root,diff);
		update(1,0,ctr-1,0,ctr-1,x);
		//cout<<a<<" "<<pre[a]<<" "<<post[a]<<" "<<-1*x<<endl;
		// for(int j=0;j<n;j++){
		// 		cout<<getsum(1,0,ctr-1,pre[j],pre[j])<<" ";
		// 	}
		// 	cout<<endl;
		update(1,0,ctr-1,pre[a],post[a],-1*x);
	}
	else{
		update(1,0,ctr-1,pre[curr],post[curr],x);
	}
}

ll handle3(int curr){
	//cout<<curr<<endl;
	if(curr==root) return getsum(1,0,ctr-1,0,ctr-1);
	else if(ispresent(curr,root)){
		int diff=level[root]-level[curr];
		diff--;
		int a=getkthpar(root,diff);
		return getsum(1,0,ctr-1,0,ctr-1)-getsum(1,0,ctr-1,pre[a],post[a]);
	}
	else{
		//cout<<pre[curr]<<" "<<post[curr]<<endl;
		return getsum(1,0,ctr-1,pre[curr],post[curr]);
	}
}

int main(){
	std::ios::sync_with_stdio(false);
	int ttt=1;
	//cin>>ttt;
	while(ttt--){
		int q,i,j;
		cin>>n>>q;
		cost.resize(n);
		adj.resize(n);
		pre.resize(n);
		post.resize(n);
		st.resize(4*n+4);
		lazy.resize(4*n+4);
		level.resize(n);
		root=0;
		for(i=0;i<n;i++){
			cin>>cost[i];
		}
		for(i=0;i<4*n+4;i++){
			st[i]=0;
			lazy[i]=0;
		}
		for(i=0;i<n-1;i++){
			int a,b;
			cin>>a>>b;
			a--; b--;
			adj[a].pb(b);
			adj[b].pb(a);
		}
		for(i=0;i<n;i++){
			for(j=0;j<H;j++){
				par[i][j]=-1;
			}
		}
		dfs(0,-1);
		for(j=1;j<H;j++){
			for(i=0;i<n;i++){
				if(par[i][j-1]==-1) par[i][j]=-1;
				else par[i][j]=par[par[i][j-1]][j-1];
			}
		}
		//cout<<getlca(1,3)<<endl;
		for(i=0;i<n;i++){
			update(1,0,ctr-1,pre[i],pre[i],cost[i]);
		}
		//cout<<pre[5]<<" "<<post[5]<<endl;
		//cout<<pre[4]<<" "<<post[4]<<endl;
		for(i=0;i<q;i++){
			int type;
			cin>>type;
			if(type==1){
				cin>>root;
				root--;
			}
			else if(type==2){
				int u,v,x;
				cin>>u>>v>>x;
				u--; v--;
				handle2(u,v,x);
			}
			else{
				int v;
				cin>>v;
				v--;
				cout<<handle3(v)<<endl;
			}
			// for(int j=0;j<n;j++){
			// 	cout<<getsum(1,0,ctr-1,pre[j],pre[j])<<" ";
			// }
			// cout<<endl;
		}
	}
	return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define mp make_pair
#define vi vector< int >
#define vb vector< bool >
#define vl vector< ll >
#define ss second
#define ff first
#define ll long long
#define pii pair< int,int >
#define pll pair< ll,ll >
#define sz(a) a.size()
#define sort(a) sort(a.begin(),a.end())
#define inf (1000*1000*1000+5)
#define all(a) a.begin(),a.end()
#define tri pair<int,pii>
#define vii vector<pii>
#define vll vector<pll>
#define viii vector<tri>
#define mod (1000*1000*1000+7)
#define moddd (1000*1000*1000+9)
#define pqueue priority_queue< int >
#define pdqueue priority_queue< int,vi ,greater< int > >
#define endl "\n"
#define flush fflush(stdout)
#define pi 3.14159265358979323846264338327950
#define primeDEN 727999983
//cout<<fixed<<setprecision(15)<<ans;

template <typename T>
void printvec(vector<T>& vec){
	for(int i=0;i<vec.size();i++){
		cout<<vec[i]<<" ";
	}
	cout<<endl;
}

#define N 100005
#define H 20

vector<vi> adj;
vi cost;
vi pre,post;
int ctr=0;
vl st,lazy;
int root;
vi level;
int par[N][H];
int n;

void update(int si,int ss,int se,int qs,int qe,ll val){
	//cout<<qs<<" "<<qe<<endl;
	if(lazy[si]!=0){
		ll len=se-ss+1;
		st[si]+=(len*lazy[si]);
		if(ss!=se){
			lazy[2*si]+=lazy[si];
			lazy[2*si+1]+=lazy[si];
		}
		lazy[si]=0;
		//return;
	}
	if(qe<ss||qs>se) return;
	if(qs<=ss&&se<=qe){
		ll len=se-ss+1;
		st[si]+=(len*val);
		if(ss!=se){
			lazy[2*si]+=val;
			lazy[2*si+1]+=val;
		}
		return;
	}
	int mid=(ss+se)/2;
	update(2*si,ss,mid,qs,qe,val);
	update(2*si+1,mid+1,se,qs,qe,val);
	st[si]=st[2*si]+st[2*si+1];
}

ll getsum(int si,int ss,int se,int qs,int qe){
	if(lazy[si]!=0){
		ll len=se-ss+1;
		st[si]+=(len*lazy[si]);
		if(ss!=se){
			lazy[2*si]+=lazy[si];
			lazy[2*si+1]+=lazy[si];
		}
		lazy[si]=0;
	}
	if(qe<ss||qs>se) return 0;
	if(qs<=ss&&se<=qe) return st[si];
	int mid=(ss+se)/2;
	return getsum(2*si,ss,mid,qs,qe)+getsum(2*si+1,mid+1,se,qs,qe);
}

void dfs(int curr,int prev){
	pre[curr]=(ctr++);
	par[curr][0]=prev;
	if(prev==-1) level[curr]=0;
	else level[curr]=level[prev]+1;
	int i;
	for(i=0;i<adj[curr].size();i++){
		if(adj[curr][i]==prev) continue;
		dfs(adj[curr][i],curr);
	}
	post[curr]=ctr-1;
}

int getkthpar(int a,int k){
	int lev=level[a]-k;
	if(lev<0) return -1;
	int i;
	for(i=H-1;i>=0;i--){
		if((level[a]-lev)>=(1<<i)) a=par[a][i];
	}
	return a;
}

int getlca(int a,int b){
	int i;
	if(level[a]<level[b]) swap(a,b);
	int diff=level[a]-level[b];
	a=getkthpar(a,diff);
	if(a==-1) return -1;
	if(a==b) return a;
	for(i=H-1;i>=0;i--){
		if(par[a][i]!=par[b][i]){
			a=par[a][i];
			b=par[b][i];
		}
	}
	return par[a][0];
}

bool ispresent(int a,int b){
	if(pre[a]<=pre[b]&&post[b]<=post[a]) return true;
	return false;
}

void handle2(int u,int v,ll x){
	int diff=level[u]-level[root];
	diff--;
	int a=getkthpar(u,diff);
	int l=getlca(u,v);
	if(ispresent(a,v)&&ispresent(root,v)&&ispresent(root,u)){
		update(1,0,ctr-1,pre[l],post[l],x);
		//cout<<"shit"<<u<<" "<<a<<" "<<l<<endl;
		return;
	}
	if(ispresent(root,v)&&ispresent(root,u)){
		//cout<<"shit"<<endl;
		update(1,0,ctr-1,0,ctr-1,x);
		return;
	}
	if(ispresent(root,u)||ispresent(root,v)){
		update(1,0,ctr-1,0,ctr-1,x);
		return;
	}
	int l1=getlca(u,root);
	int l2=getlca(v,root);
	int l3=getlca(u,v);
	if(level[l1]>level[l2]) l=l1;
	else l=l2;
	if(level[l]<level[l3]) l=l3;
	int curr=l;
	//cout<<curr<<endl;
	if(curr==root) update(1,0,ctr-1,0,ctr-1,x);
	else if(ispresent(curr,root)){
		int diff=level[root]-level[curr];
		diff--;
		int a=getkthpar(root,diff);
		update(1,0,ctr-1,0,ctr-1,x);
		//cout<<a<<" "<<pre[a]<<" "<<post[a]<<" "<<-1*x<<endl;
		// for(int j=0;j<n;j++){
		// 		cout<<getsum(1,0,ctr-1,pre[j],pre[j])<<" ";
		// 	}
		// 	cout<<endl;
		update(1,0,ctr-1,pre[a],post[a],-1*x);
	}
	else{
		update(1,0,ctr-1,pre[curr],post[curr],x);
	}
}

ll handle3(int curr){
	//cout<<curr<<endl;
	if(curr==root) return getsum(1,0,ctr-1,0,ctr-1);
	else if(ispresent(curr,root)){
		int diff=level[root]-level[curr];
		diff--;
		int a=getkthpar(root,diff);
		return getsum(1,0,ctr-1,0,ctr-1)-getsum(1,0,ctr-1,pre[a],post[a]);
	}
	else{
		//cout<<pre[curr]<<" "<<post[curr]<<endl;
		return getsum(1,0,ctr-1,pre[curr],post[curr]);
	}
}

int main(){
	std::ios::sync_with_stdio(false);
	int ttt=1;
	//cin>>ttt;
	while(ttt--){
		int q,i,j;
		cin>>n>>q;
		cost.resize(n);
		adj.resize(n);
		pre.resize(n);
		post.resize(n);
		st.resize(4*n+4);
		lazy.resize(4*n+4);
		level.resize(n);
		root=0;
		for(i=0;i<n;i++){
			cin>>cost[i];
		}
		for(i=0;i<4*n+4;i++){
			st[i]=0;
			lazy[i]=0;
		}
		for(i=0;i<n-1;i++){
			int a,b;
			cin>>a>>b;
			a--; b--;
			adj[a].pb(b);
			adj[b].pb(a);
		}
		for(i=0;i<n;i++){
			for(j=0;j<H;j++){
				par[i][j]=-1;
			}
		}
		dfs(0,-1);
		for(j=1;j<H;j++){
			for(i=0;i<n;i++){
				if(par[i][j-1]==-1) par[i][j]=-1;
				else par[i][j]=par[par[i][j-1]][j-1];
			}
		}
		//cout<<getlca(1,3)<<endl;
		for(i=0;i<n;i++){
			update(1,0,ctr-1,pre[i],pre[i],cost[i]);
		}
		//cout<<pre[5]<<" "<<post[5]<<endl;
		//cout<<pre[4]<<" "<<post[4]<<endl;
		for(i=0;i<q;i++){
			int type;
			cin>>type;
			if(type==1){
				cin>>root;
				root--;
			}
			else if(type==2){
				int u,v,x;
				cin>>u>>v>>x;
				u--; v--;
				handle2(u,v,x);
			}
			else{
				int v;
				cin>>v;
				v--;
				cout<<handle3(v)<<endl;
			}
			// for(int j=0;j<n;j++){
			// 	cout<<getsum(1,0,ctr-1,pre[j],pre[j])<<" ";
			// }
			// cout<<endl;
		}
	}
	return 0;
}


#include<iostream>
#include<cstdio>
#include<cmath>
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=200005;
int dist[N],root=1,q,pos[N],tree[N<<2],lazy[N<<2],in[N],out[N],ti,n,a[N],an[N],nextt[N],son[N],ed[N],dp[N][22],nedge;
inline void aedge(int a,int b){
	nextt[++nedge]=son[a];
	son[a]=nedge;
	ed[nedge]=b;
}
inline void dfs(int p,int fa){
	dp[p][0]=fa; pos[in[p]=++ti]=p; dist[p]=dist[fa]+1;
	for(int i=son[p];i;i=nextt[i])if(ed[i]!=fa){
		dfs(ed[i],p);
	}
	out[p]=ti;
}
inline void cao(int nod,int l,int r,int x){
	tree[nod]+=x*(r-l+1);
}
inline void pushdown(int nod,int l,int r){
	if(!lazy[nod])return; int mid=(l+r)>>1;
	lazy[nod<<1]+=lazy[nod]; lazy[nod<<1|1]+=lazy[nod]; cao(nod<<1,l,mid,lazy[nod]); cao(nod<<1|1,mid+1,r,lazy[nod]); lazy[nod]=0;
}
inline void insert(int l,int r,int i,int j,int s,int nod){
    int mid=(l+r)>>1;
	if(l==i&&r==j){
		lazy[nod]+=s; cao(nod,l,r,s); return;
	}
    pushdown(nod,l,r);
    if(j<=mid)insert(l,mid,i,j,s,nod<<1); else
    if(i>mid)insert(mid+1,r,i,j,s,nod<<1|1); else{
    	insert(l,mid,i,mid,s,nod<<1); insert(mid+1,r,mid+1,j,s,nod<<1|1);
	}
	tree[nod]=tree[nod<<1]+tree[nod<<1|1];
}
inline int ask(int l,int r,int i,int j,int nod){
	if(l==i&&r==j)return tree[nod];
    int mid=(l+r)>>1;
    pushdown(nod,l,r);
    if(j<=mid)return ask(l,mid,i,j,nod<<1); else
    if(i>mid)return ask(mid+1,r,i,j,nod<<1|1); else{
    	return ask(l,mid,i,mid,nod<<1)+ask(mid+1,r,mid+1,j,nod<<1|1);
	}
}
inline void build(int l,int r,int nod){
	int mid=(l+r)>>1; lazy[nod]=0;
	if (l==r){tree[nod]=a[pos[l]]; return;}
	build(l,mid,nod<<1); build(mid+1,r,nod<<1|1);
	tree[nod]=tree[nod<<1]+tree[nod<<1|1];
}
inline int read(){
	int x = 0; char ch = getchar(); bool positive = 1;
	for (; !isdigit(ch); ch = getchar())	if (ch == '-')	positive = 0;
	for (; isdigit(ch); ch = getchar())	x = x * 10 + ch - '0';
	return positive ? x : -x;
}
inline void write(int a){
    if(a>=10)write(a/10);
    putchar('0'+a%10);
}
inline void writeln(int a){
     if(a<0){
          a=-a; putchar('-');
     }
    write(a); puts("");
}
inline int fa(int x,int y){
	return in[x]<=in[y]&&out[x]>=out[y];
}
inline int LCA(int a,int b){
	if(fa(a,b))return a; else if(fa(b,a))return b;
	int k=a;
	for(int j=20;j>=0;j--)if(dp[k][j]&&!fa(dp[k][j],b))k=dp[k][j];//cout<<a<<" "<<b<<" "<<k<<endl;
	return dp[k][0];
}
inline int query(int u,int v){
	for(int i=20;i>=0;i--)if(dp[u][i]&&!fa(dp[u][i],v))u=dp[u][i];
	return u;
}
int query(int nod){
	int ans;
	if(fa(nod,root)){
		ans=ask(1,n,1,n,1); if(nod==root)return ans;
		int tt=query(root,nod);
		ans-=ask(1,n,in[tt],out[tt],1);
	}else{
		ans=ask(1,n,in[nod],out[nod],1);
	}
	return ans;
}
void update(int nod,int x){
	if(fa(nod,root)){
		insert(1,n,1,n,x,1); if(nod==root)return;
		int tt=query(root,nod);
		insert(1,n,in[tt],out[tt],-x,1);
	}else{
		insert(1,n,in[nod],out[nod],x,1);
	}
}
inline int qiu(int a,int b){
	int t=LCA(a,b);
	return dist[a]+dist[b]-(dist[t]<<1);
}
inline int find(int a,int b,int c){
	int t=qiu(a,c)<qiu(b,c)?a:b;
	int tt=LCA(a,c);
	if(!fa(tt,b)&&qiu(tt,c)<qiu(t,c))t=tt;
	return t;
}
signed main(){
	n=read();q=read();
	for(int i=1;i<=n;i++)a[i]=read();
	for(int i=1;i<n;i++){
		int s=read(),t=read();
		aedge(s,t); aedge(t,s);
	}
	dfs(1,0);
	build(1,n,1);
	for(int j=1;j<=20;j++){
		for(int i=1;i<=n;i++){
			dp[i][j]=dp[dp[i][j-1]][j-1];
		}
	}
	while(q--){
		int op=read();
		if(op==1){
			root=read();
		}else if(op==2){
			int u=read(),v=read(),t;
			int tt=LCA(u,root);
			int t1=find(u,tt,v),t2=find(root,tt,v);
			t=qiu(t1,v)<qiu(t2,v)?t1:t2;
			update(t,read());
		}else{
			int x=read();
			writeln(query(x));
		}
	}
	//cout<<ask(1,n,1,n,1)<<endl;
}


#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<cctype>
#define lc (o<<1)
#define rc (o<<1|1)
using namespace std;
typedef long long ll;

inline ll read() {
	char ch = getchar(); ll x = 0; int op = 1;
	for(; !isdigit(ch); ch = getchar()) if(ch == '-') op = -1;
	for(; isdigit(ch); ch = getchar()) x = x*10+ch-'0';
	return x*op;
}
inline void write(ll a) {
	if(a < 0) putchar('-'), a = -a;
	if(a >= 10) write(a/10); putchar('0'+a%10);
}

const int N = 200010;
int n, m, cnt, clk, rt;
int a[N], val[N], head[N], depth[N], f[N][25], in[N], out[N];
ll sum[N<<2], tag[N<<2];
struct edge {
	int to, nxt;
	edge() {}
	edge(int x, int y) { to = x, nxt = y; }
}e[N<<1];

//segment tree
inline void build(int o, int l, int r) {
	if(l == r) { sum[o] = val[l]; return; }
	int mid = l+r>>1;
	build(lc, l, mid); build(rc, mid+1, r);
	sum[o] = sum[lc]+sum[rc];
}
inline void pushdown(int o, int l, int r) {
	if(!tag[o]) return;
	tag[lc] += tag[o]; tag[rc] += tag[o];
	int mid = l+r>>1;
	sum[lc] += (ll)tag[o]*(mid-l+1); sum[rc] += (ll)tag[o]*(r-mid);
	tag[o] = 0;
}
inline void update(int o, int l, int r, int x, int y, int w) {
	if(l == x && r == y) {
		sum[o] += (ll)(r-l+1)*w; tag[o] += w; return;
	}
	pushdown(o, l, r);
	int mid = l+r>>1;
	if(y <= mid) update(lc, l, mid, x, y, w);
	else if(x > mid) update(rc, mid+1, r, x, y, w);
	else update(lc, l, mid, x, mid, w), update(rc, mid+1, r, mid+1, y, w);
	sum[o] = sum[lc]+sum[rc];
}
inline ll query(int o, int l, int r, int x, int y) {
	if(l == x && r == y) return sum[o];
	pushdown(o, l, r);
	ll ret = 0; int mid = l+r>>1;
	if(y <= mid) return query(lc, l, mid, x, y);
	else if(x > mid) return query(rc, mid+1, r, x, y);
	else return query(lc, l, mid, x, mid) + query(rc, mid+1, r, mid+1, y);
}

inline void addedge(int x, int y) { e[++ cnt] = edge(y, head[x]); head[x] = cnt; }
inline bool isAncestor(int x, int y) { return in[x] <= in[y] && out[x] >= out[y]; }
inline void dfs(int u, int lst, int s) {
	depth[u] = s; f[u][0] = lst; in[u] = ++ clk; val[clk] = a[u];
	for(int i = head[u]; i; i = e[i].nxt) if(e[i].to != lst) dfs(e[i].to, u, s+1);
	out[u] = clk;
}
inline int lca(int x, int y) {
	if(depth[x] < depth[y]) swap(x, y);
	int tmp = depth[x]-depth[y];
	for(int i = 20; i >= 0; i --)
		if(tmp>>i&1) x = f[x][i];
	if(x == y) return x;
	for(int i = 20; i >= 0; i --)
		if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
	return f[x][0];
}
inline int getlca(int rt, int x, int y) {
	if(isAncestor(rt, x) && isAncestor(rt, y)) return lca(x, y);
	else if(isAncestor(rt, x) || isAncestor(rt, y)) return rt;
	int u = lca(x, rt), v = lca(y, rt);
	if(depth[u] > depth[v]) return u; else return v;
}
inline int find(int x, int y) {
	int tmp = depth[x]-depth[y]-1;
	for(int i = 20; i >= 0; i --)
		if(tmp>>i&1) x = f[x][i];
	return x;
}
inline void add(int rt, int x, int w) {
	if(rt == x) update(1, 1, n, 1, n, w);
	else if(!isAncestor(x, rt)) update(1, 1, n, in[x], out[x], w);
	else {
		int y = find(rt, x);
		update(1, 1, n, 1, in[y]-1, w);
		update(1, 1, n, out[y]+1, n, w);
	}
}
inline ll qry(int rt, int x) {
	if(rt == x) return sum[1];
	else if(!isAncestor(x, rt)) return query(1, 1, n, in[x], out[x]);
	else {
		int y = find(rt, x);
		return query(1, 1, n, 1, in[y]-1) + query(1, 1, n, out[y]+1, n);
	}
}
int main() {
	n = read(), m = read();
	for(int i = 1; i <= n; i ++) a[i] = read();
	for(int i = 1; i < n; i ++) {
		int x = read(), y = read();
		addedge(x, y); addedge(y, x);
	}
	rt = 1;
	dfs(1, 0, 0); build(1, 1, n);
	for(int j = 1; j <= 20; j ++)
		for(int i = 1; i <= n; i ++) f[i][j] = f[f[i][j-1]][j-1];
	while(m --) {
		int opt = read(), x, y, z, w;
		if(opt == 1) rt = read();
		else if(opt == 2) {
			x = read(), y = read(), w = read();
			z = getlca(rt, x, y);
			add(rt, z, w);
		} else {
			x = read();
			write(qry(rt, x)); puts("");
		}
	}
	return 0;
}


#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<cctype>
#define lc (o<<1)
#define rc (o<<1|1)
using namespace std;
typedef long long ll;

inline ll read() {
	char ch = getchar(); ll x = 0; int op = 1;
	for(; !isdigit(ch); ch = getchar()) if(ch == '-') op = -1;
	for(; isdigit(ch); ch = getchar()) x = x*10+ch-'0';
	return x*op;
}
inline void write(ll a) {
	if(a < 0) putchar('-'), a = -a;
	if(a >= 10) write(a/10); putchar('0'+a%10);
}

const int N = 200010;
int n, m, cnt, clk, rt;
int a[N], val[N], head[N], depth[N], f[N][25], in[N], out[N];
ll sum[N<<2], tag[N<<2];
struct edge {
	int to, nxt;
	edge() {}
	edge(int x, int y) { to = x, nxt = y; }
}e[N<<1];

//segment tree
inline void build(int o, int l, int r) {
	if(l == r) { sum[o] = val[l]; return; }
	int mid = l+r>>1;
	build(lc, l, mid); build(rc, mid+1, r);
	sum[o] = sum[lc]+sum[rc];
}
inline void pushdown(int o, int l, int r) {
	if(!tag[o]) return;
	tag[lc] += tag[o]; tag[rc] += tag[o];
	int mid = l+r>>1;
	sum[lc] += (ll)tag[o]*(mid-l+1); sum[rc] += (ll)tag[o]*(r-mid);
	tag[o] = 0;
}
inline void update(int o, int l, int r, int x, int y, int w) {
	if(x > y) return;
	if(l == x && r == y) {
		sum[o] += (ll)(r-l+1)*w; tag[o] += w; return;
	}
	pushdown(o, l, r);
	int mid = l+r>>1;
	if(y <= mid) update(lc, l, mid, x, y, w);
	else if(x > mid) update(rc, mid+1, r, x, y, w);
	else update(lc, l, mid, x, mid, w), update(rc, mid+1, r, mid+1, y, w);
	sum[o] = sum[lc]+sum[rc];
}
inline ll query(int o, int l, int r, int x, int y) {
	if(x > y) return 0;
	if(l == x && r == y) return sum[o];
	pushdown(o, l, r);
	ll ret = 0; int mid = l+r>>1;
	if(y <= mid) return query(lc, l, mid, x, y);
	else if(x > mid) return query(rc, mid+1, r, x, y);
	else return query(lc, l, mid, x, mid) + query(rc, mid+1, r, mid+1, y);
}

inline void addedge(int x, int y) { e[++ cnt] = edge(y, head[x]); head[x] = cnt; }
inline bool isAncestor(int x, int y) { return in[x] <= in[y] && out[x] >= out[y]; }
inline void dfs(int u, int lst, int s) {
	depth[u] = s; f[u][0] = lst; in[u] = ++ clk; val[clk] = a[u];
	for(int i = head[u]; i; i = e[i].nxt) if(e[i].to != lst) dfs(e[i].to, u, s+1);
	out[u] = clk;
}
inline int lca(int x, int y) {
	if(depth[x] < depth[y]) swap(x, y);
	int tmp = depth[x]-depth[y];
	for(int i = 20; i >= 0; i --)
		if(tmp>>i&1) x = f[x][i];
	if(x == y) return x;
	for(int i = 20; i >= 0; i --)
		if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
	return f[x][0];
}
inline int getlca(int rt, int x, int y) {
	if(isAncestor(rt, x) && isAncestor(rt, y)) return lca(x, y);
	else if(isAncestor(rt, x) || isAncestor(rt, y)) return rt;
	int u = lca(x, rt), v = lca(y, rt);
	if(depth[u] > depth[v]) return u; else return v;
}
inline int find(int x, int y) {
	int tmp = depth[x]-depth[y]-1;
	for(int i = 20; i >= 0; i --)
		if(tmp>>i&1) x = f[x][i];
	return x;
}
inline void add(int rt, int x, int w) {
	if(rt == x) update(1, 1, n, 1, n, w);
	else if(!isAncestor(x, rt)) update(1, 1, n, in[x], out[x], w);
	else {
		int y = find(rt, x);
		update(1, 1, n, 1, in[y]-1, w);
		update(1, 1, n, out[y]+1, n, w);
	}
}
inline ll qry(int rt, int x) {
	if(rt == x) return sum[1];
	else if(!isAncestor(x, rt)) return query(1, 1, n, in[x], out[x]);
	else {
		int y = find(rt, x);
		return query(1, 1, n, 1, in[y]-1) + query(1, 1, n, out[y]+1, n);
	}
}
int main() {
	/*freopen("E.in", "r", stdin);
	freopen("E.out", "w", stdout);*/
	n = read(), m = read();
	for(int i = 1; i <= n; i ++) a[i] = read();
	for(int i = 1; i < n; i ++) {
		int x = read(), y = read();
		addedge(x, y); addedge(y, x);
	}
	rt = 1;
	dfs(1, 0, 0);
	build(1, 1, n);
	for(int j = 1; j <= 20; j ++)
		for(int i = 1; i <= n; i ++) f[i][j] = f[f[i][j-1]][j-1];
	while(m --) {
		int opt = read(), x, y, z, w;
		if(opt == 1) rt = read();
		else if(opt == 2) {
			x = read(), y = read(), w = read();
			z = getlca(rt, x, y);
			add(rt, z, w);
		} else {
			x = read();
			write(qry(rt, x)); puts("");
		}
	}
	return 0;
}


#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<cctype>
#define lc (o<<1)
#define rc (o<<1|1)
using namespace std;
typedef long long ll;

inline ll read() {
	char ch = getchar(); ll x = 0; int op = 1;
	for(; !isdigit(ch); ch = getchar()) if(ch == '-') op = -1;
	for(; isdigit(ch); ch = getchar()) x = x*10+ch-'0';
	return x*op;
}
inline void write(ll a) {
	if(a < 0) putchar('-'), a = -a;
	if(a >= 10) write(a/10); putchar('0'+a%10);
}

const int N = 100010;
int n, m, cnt, clk, rt;
int a[N], val[N], head[N], depth[N], f[N][20], in[N], out[N];
ll sum[N<<2], tag[N<<2];
struct edge {
	int to, nxt;
	edge() {}
	edge(int x, int y) { to = x, nxt = y; }
}e[N<<1];

//segment tree
inline void build(int o, int l, int r) {
	if(l == r) { sum[o] = val[l]; return; }
	int mid = l+r>>1;
	build(lc, l, mid); build(rc, mid+1, r);
	sum[o] = sum[lc]+sum[rc];
}
inline void pushdown(int o, int l, int r) {
	if(!tag[o]) return;
	tag[lc] += tag[o]; tag[rc] += tag[o];
	int mid = l+r>>1;
	sum[lc] += (ll)tag[o]*(mid-l+1); sum[rc] += (ll)tag[o]*(r-mid);
	tag[o] = 0;
}
inline void update(int o, int l, int r, int x, int y, int w) {
	if(l >= x && r <= y) {
		sum[o] += (ll)(r-l+1)*w; tag[o] += w; return;
	}
	pushdown(o, l, r);
	int mid = l+r>>1;
	if(x <= mid) update(lc, l, mid, x, y, w);
	if(y > mid) update(rc, mid+1, r, x, y, w);
	sum[o] = sum[lc]+sum[rc];
}
inline ll query(int o, int l, int r, int x, int y) {
	if(l >= x && r <= y) return sum[o];
	pushdown(o, l, r);
	ll ret = 0; int mid = l+r>>1;
	if(x <= mid) ret += query(lc, l, mid, x, y);
	if(y > mid) ret += query(rc, mid+1, r, x, y);
	return ret;
}

inline void addedge(int x, int y) { e[++ cnt] = edge(y, head[x]); head[x] = cnt; }
inline bool isAncestor(int x, int y) { return in[x] <= in[y] && out[x] >= out[y]; }
inline void dfs(int u, int lst, int s) {
	depth[u] = s; f[u][0] = lst; in[u] = ++ clk; val[clk] = a[u];
	for(int i = head[u]; i; i = e[i].nxt) if(e[i].to != lst) dfs(e[i].to, u, s+1);
	out[u] = clk;
}
inline int lca(int x, int y) {
	if(depth[x] < depth[y]) swap(x, y);
	int tmp = depth[x]-depth[y];
	for(int i = 17; i >= 0; i --)
		if(tmp>>i&1) x = f[x][i];
	if(x == y) return x;
	for(int i = 17; i >= 0; i --)
		if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
	return f[x][0];
}
inline int getlca(int rt, int x, int y) {
	if(isAncestor(rt, x) && isAncestor(rt, y)) return lca(x, y);
	else if(isAncestor(rt, x) || isAncestor(rt, y)) return rt;
	int u = lca(x, rt), v = lca(y, rt);
	if(depth[u] > depth[v]) return u; else return v;
}
inline int find(int x, int y) {
	int tmp = depth[x]-depth[y]-1;
	for(int i = 17; i >= 0; i --)
		if(tmp>>i&1) x = f[x][i];
	return x;
}
inline void add(int rt, int x, int w) {
	if(rt == x) update(1, 1, n, 1, n, w);
	else if(isAncestor(rt, x)) update(1, 1, n, in[x], out[x], w);
	else {
		int y = find(rt, x);
		update(1, 1, n, 1, in[y]-1, w);
		update(1, 1, n, out[y]+1, n, w);
	}
}
inline ll qry(int rt, int x) {
	if(rt == x) return sum[1];
	else if(isAncestor(rt, x)) return query(1, 1, n, in[x], out[x]);
	else {
		int y = find(rt, x);
		return query(1, 1, n, 1, in[y]-1) + query(1, 1, n, out[y]+1, n);
	}
}
int main() {
	n = read(), m = read();
	for(int i = 1; i <= n; i ++) a[i] = read();
	for(int i = 1; i < n; i ++) {
		int x = read(), y = read();
		addedge(x, y); addedge(y, x);
	}
	rt = 1;
	dfs(1, 0, 0); build(1, 1, n);
	for(int j = 1; j <= 17; j ++)
		for(int i = 1; i <= n; i ++) f[i][j] = f[f[i][j-1]][j-1];
	while(m --) {
		int opt = read(), x, y, z, w;
		if(opt == 1) rt = read();
		else if(opt == 2) {
			x = read(), y = read(), w = read();
			z = getlca(rt, x, y);
			//printf("lca = %d\n", z);
			add(rt, z, w);
		} else {
			x = read();
			write(qry(rt, x)); puts("");
		}
	}
	return 0;
}


#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<cctype>
#define lc (o<<1)
#define rc (o<<1|1)
using namespace std;
typedef long long ll;

inline ll read() {
	char ch = getchar(); ll x = 0; int op = 1;
	for(; !isdigit(ch); ch = getchar()) if(ch == '-') op = -1;
	for(; isdigit(ch); ch = getchar()) x = x*10+ch-'0';
	return x*op;
}
inline void write(ll a) {
	if(a < 0) putchar('-'), a = -a;
	if(a >= 10) write(a/10); putchar('0'+a%10);
}

const int N = 200010;
int n, m, cnt, clk, rt;
int a[N], val[N], head[N], depth[N], f[N][25], in[N], out[N];
ll sum[N<<2], tag[N<<2];
struct edge {
	int to, nxt;
	edge() {}
	edge(int x, int y) { to = x, nxt = y; }
}e[N<<1];

//segment tree
inline void build(int o, int l, int r) {
	if(l == r) { sum[o] = val[l]; return; }
	int mid = l+r>>1;
	build(lc, l, mid); build(rc, mid+1, r);
	sum[o] = sum[lc]+sum[rc];
}
inline void pushdown(int o, int l, int r) {
	if(!tag[o]) return;
	tag[lc] += tag[o]; tag[rc] += tag[o];
	int mid = l+r>>1;
	sum[lc] += (ll)tag[o]*(mid-l+1); sum[rc] += (ll)tag[o]*(r-mid);
	tag[o] = 0;
}
inline void update(int o, int l, int r, int x, int y, int w) {
	if(x > y) return;
	if(l == x && r == y) {
		sum[o] += (ll)(r-l+1)*w; tag[o] += w; return;
	}
	pushdown(o, l, r);
	int mid = l+r>>1;
	if(y <= mid) update(lc, l, mid, x, y, w);
	else if(x > mid) update(rc, mid+1, r, x, y, w);
	else update(lc, l, mid, x, mid, w), update(rc, mid+1, r, mid+1, y, w);
	sum[o] = sum[lc]+sum[rc];
}
inline ll query(int o, int l, int r, int x, int y) {
	//printf("%d %d %d %d\n", l, r, x, y);
	if(x > y) return 0;
	if(l == x && r == y) return sum[o];
	pushdown(o, l, r);
	ll ret = 0; int mid = l+r>>1;
	if(y <= mid) return query(lc, l, mid, x, y);
	else if(x > mid) return query(rc, mid+1, r, x, y);
	else return query(lc, l, mid, x, mid) + query(rc, mid+1, r, mid+1, y);
}

inline void addedge(int x, int y) { e[++ cnt] = edge(y, head[x]); head[x] = cnt; }
inline bool isAncestor(int x, int y) { return in[x] <= in[y] && out[x] >= out[y]; }
inline void dfs(int u, int lst, int s) {
	depth[u] = s; f[u][0] = lst; in[u] = ++ clk; val[clk] = a[u];
	for(int i = head[u]; i; i = e[i].nxt) if(e[i].to != lst) dfs(e[i].to, u, s+1);
	out[u] = clk;
}
inline int lca(int x, int y) {
	if(depth[x] < depth[y]) swap(x, y);
	int tmp = depth[x]-depth[y];
	for(int i = 20; i >= 0; i --)
		if(tmp>>i&1) x = f[x][i];
	if(x == y) return x;
	for(int i = 20; i >= 0; i --)
		if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
	return f[x][0];
}
inline int getlca(int rt, int x, int y) {
	int u = lca(x, rt), v = lca(y, rt), w = lca(x, y);
	return u^v^w;
}
inline int find(int x, int y) {
	int tmp = depth[x]-depth[y]-1;
	for(int i = 20; i >= 0; i --)
		if(tmp>>i&1) x = f[x][i];
	return x;
}
inline void add(int rt, int x, int w) {
	if(rt == x) update(1, 1, n, 1, n, w);
	else if(!isAncestor(x, rt)) update(1, 1, n, in[x], out[x], w);
	else {
		int y = find(rt, x);
		update(1, 1, n, 1, in[y]-1, w);
		update(1, 1, n, out[y]+1, n, w);
	}
}
inline ll qry(int rt, int x) {
	if(rt == x) return sum[1];
	else if(!isAncestor(x, rt)) return query(1, 1, n, in[x], out[x]);
	else {
		int y = find(rt, x); //printf("y = %d\n", y);
		return query(1, 1, n, 1, in[y]-1) + query(1, 1, n, out[y]+1, n);
	}
}
int main() {
	/*freopen("E.in", "r", stdin);
	freopen("E.out", "w", stdout);*/
	n = read(), m = read();
	for(int i = 1; i <= n; i ++) a[i] = read();
	for(int i = 1; i < n; i ++) {
		int x = read(), y = read();
		addedge(x, y); addedge(y, x);
	}
	rt = 1;
	dfs(1, 0, 0);
	//for(int i = 1; i <= n; i ++) printf("%d %d\n", in[i], out[i]);
	build(1, 1, n);
	for(int j = 1; j <= 20; j ++)
		for(int i = 1; i <= n; i ++) f[i][j] = f[f[i][j-1]][j-1];
	while(m --) {
		int opt = read(), x, y, z, w;
		if(opt == 1) rt = read();
		else if(opt == 2) {
			x = read(), y = read(), w = read();
			z = getlca(rt, x, y);
			add(rt, z, w);
		} else {
			x = read();
			write(qry(rt, x)); puts("");
		}
	}
	return 0;
}


#include<iostream>
#include<cstdio>
#include<cmath>
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=200005;
int dist[N],root=1,q,pos[N],tree[N<<2],lazy[N<<2],in[N],out[N],ti,n,a[N],an[N],nextt[N],son[N],ed[N],dp[N][22],nedge;
inline void aedge(int a,int b){
	nextt[++nedge]=son[a];
	son[a]=nedge;
	ed[nedge]=b;
}
inline void dfs(int p,int fa){
	dp[p][0]=fa; pos[in[p]=++ti]=p; dist[p]=dist[fa]+1;
	for(int i=son[p];i;i=nextt[i])if(ed[i]!=fa){
		dfs(ed[i],p);
	}
	out[p]=ti;
}
inline void cao(int nod,int l,int r,int x){
	tree[nod]+=x*(r-l+1);
}
inline void pushdown(int nod,int l,int r){
	if(!lazy[nod])return; int mid=(l+r)>>1;
	lazy[nod<<1]+=lazy[nod]; lazy[nod<<1|1]+=lazy[nod]; cao(nod<<1,l,mid,lazy[nod]); cao(nod<<1|1,mid+1,r,lazy[nod]); lazy[nod]=0;
}
inline void insert(int l,int r,int i,int j,int s,int nod){
    int mid=(l+r)>>1;
	if(l==i&&r==j){
		lazy[nod]+=s; cao(nod,l,r,s); return;
	}
    pushdown(nod,l,r);
    if(j<=mid)insert(l,mid,i,j,s,nod<<1); else
    if(i>mid)insert(mid+1,r,i,j,s,nod<<1|1); else{
    	insert(l,mid,i,mid,s,nod<<1); insert(mid+1,r,mid+1,j,s,nod<<1|1);
	}
	tree[nod]=tree[nod<<1]+tree[nod<<1|1];
}
inline int ask(int l,int r,int i,int j,int nod){
	if(l==i&&r==j)return tree[nod];
    int mid=(l+r)>>1;
    pushdown(nod,l,r);
    if(j<=mid)return ask(l,mid,i,j,nod<<1); else
    if(i>mid)return ask(mid+1,r,i,j,nod<<1|1); else{
    	return ask(l,mid,i,mid,nod<<1)+ask(mid+1,r,mid+1,j,nod<<1|1);
	}
}
inline void build(int l,int r,int nod){
	int mid=(l+r)>>1; lazy[nod]=0;
	if (l==r){tree[nod]=a[pos[l]]; return;}
	build(l,mid,nod<<1); build(mid+1,r,nod<<1|1);
	tree[nod]=tree[nod<<1]+tree[nod<<1|1];
}
inline int read(){
	int x = 0; char ch = getchar(); bool positive = 1;
	for (; !isdigit(ch); ch = getchar())	if (ch == '-')	positive = 0;
	for (; isdigit(ch); ch = getchar())	x = x * 10 + ch - '0';
	return positive ? x : -x;
}
inline void write(int a){
    if(a>=10)write(a/10);
    putchar('0'+a%10);
}
inline void writeln(int a){
    if(a<0) putchar('-'), a=-a; write(a); puts("");
}
inline int fa(int x,int y){
	return in[x]<=in[y]&&out[x]>=out[y];
}
inline int LCA(int a,int b){
	if(fa(a,b))return a; else if(fa(b,a))return b;
	int k=a;
	for(int j=20;j>=0;j--)if(dp[k][j]&&!fa(dp[k][j],b))k=dp[k][j];//cout<<a<<" "<<b<<" "<<k<<endl;
	return dp[k][0];
}
inline int query(int u,int v){
	for(int i=20;i>=0;i--)if(dp[u][i]&&!fa(dp[u][i],v))u=dp[u][i];
	return u;
}
int query(int nod){
	int ans;
	if(fa(nod,root)){
		ans=ask(1,n,1,n,1); if(nod==root)return ans;
		int tt=query(root,nod);
		ans-=ask(1,n,in[tt],out[tt],1);
	}else{
		ans=ask(1,n,in[nod],out[nod],1);
	}
	return ans;
}
void update(int nod,int x){
	if(fa(nod,root)){
		insert(1,n,1,n,x,1); if(nod==root)return;
		int tt=query(root,nod);
		insert(1,n,in[tt],out[tt],-x,1);
	}else{
		insert(1,n,in[nod],out[nod],x,1);
	}
}
inline int qiu(int a,int b){
	int t=LCA(a,b);
	return dist[a]+dist[b]-(dist[t]<<1);
}
inline int find(int a,int b,int c){
	int t=qiu(a,c)<qiu(b,c)?a:b;
	int tt=LCA(a,c);
	if(!fa(tt,b)&&qiu(tt,c)<qiu(t,c))t=tt;
	return t;
}
signed main(){
	n=read();q=read();
	for(int i=1;i<=n;i++)a[i]=read();
	for(int i=1;i<n;i++){
		int s=read(),t=read();
		aedge(s,t); aedge(t,s);
	}
	dfs(1,0);
	build(1,n,1);
	for(int j=1;j<=20;j++){
		for(int i=1;i<=n;i++){
			dp[i][j]=dp[dp[i][j-1]][j-1];
		}
	}
	while(q--){
		int op=read();
		if(op==1){
			root=read();
		}else if(op==2){
			int u=read(),v=read(),t;
			int tt=LCA(u,root);
			int t1=find(u,tt,v),t2=find(root,tt,v);
			t=qiu(t1,v)<qiu(t2,v)?t1:t2;
			update(t,read());
		}else{
			int x=read();
			writeln(query(x));
		}
	}
	//cout<<ask(1,n,1,n,1)<<endl;
}


#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<cctype>
#define lc (o<<1)
#define rc (o<<1|1)
using namespace std;
typedef long long ll;

inline ll read() {
	char ch = getchar(); ll x = 0; int op = 1;
	for(; !isdigit(ch); ch = getchar()) if(ch == '-') op = -1;
	for(; isdigit(ch); ch = getchar()) x = x*10+ch-'0';
	return x*op;
}
inline void write(ll a) {
	if(a < 0) putchar('-'), a = -a;
	if(a >= 10) write(a/10); putchar('0'+a%10);
}

const int N = 200010;
int n, m, cnt, clk, rt;
int a[N], val[N], head[N], depth[N], f[N][20], in[N], out[N];
ll sum[N<<2], tag[N<<2];
struct edge {
	int to, nxt;
	edge() {}
	edge(int x, int y) { to = x, nxt = y; }
}e[N<<1];

//segment tree
inline void build(int o, int l, int r) {
	if(l == r) { sum[o] = val[l]; return; }
	int mid = l+r>>1;
	build(lc, l, mid); build(rc, mid+1, r);
	sum[o] = sum[lc]+sum[rc];
}
inline void pushdown(int o, int l, int r) {
	if(!tag[o]) return;
	tag[lc] += tag[o]; tag[rc] += tag[o];
	int mid = l+r>>1;
	sum[lc] += (ll)tag[o]*(mid-l+1); sum[rc] += (ll)tag[o]*(r-mid);
	tag[o] = 0;
}
inline void update(int o, int l, int r, int x, int y, int w) {
	if(l >= x && r <= y) {
		sum[o] += (ll)(r-l+1)*w; tag[o] += w; return;
	}
	pushdown(o, l, r);
	int mid = l+r>>1;
	if(x <= mid) update(lc, l, mid, x, y, w);
	if(y > mid) update(rc, mid+1, r, x, y, w);
	sum[o] = sum[lc]+sum[rc];
}
inline ll query(int o, int l, int r, int x, int y) {
	if(l >= x && r <= y) return sum[o];
	pushdown(o, l, r);
	ll ret = 0; int mid = l+r>>1;
	if(x <= mid) ret += query(lc, l, mid, x, y);
	if(y > mid) ret += query(rc, mid+1, r, x, y);
	return ret;
}

inline void addedge(int x, int y) { e[++ cnt] = edge(y, head[x]); head[x] = cnt; }
inline bool isAncestor(int x, int y) { return in[x] <= in[y] && out[x] >= out[y]; }
inline void dfs(int u, int lst, int s) {
	depth[u] = s; f[u][0] = lst; in[u] = ++ clk; val[clk] = a[u];
	for(int i = head[u]; i; i = e[i].nxt) if(e[i].to != lst) dfs(e[i].to, u, s+1);
	out[u] = clk;
}
inline int lca(int x, int y) {
	if(depth[x] < depth[y]) swap(x, y);
	int tmp = depth[x]-depth[y];
	for(int i = 18; i >= 0; i --)
		if(tmp>>i&1) x = f[x][i];
	if(x == y) return x;
	for(int i = 18; i >= 0; i --)
		if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
	return f[x][0];
}
inline int getlca(int rt, int x, int y) {
	if(isAncestor(rt, x) && isAncestor(rt, y)) return lca(x, y);
	else if(isAncestor(rt, x) || isAncestor(rt, y)) return rt;
	int u = lca(x, rt), v = lca(y, rt);
	if(depth[u] > depth[v]) return u; else return v;
}
inline int find(int x, int y) {
	int tmp = depth[x]-depth[y]-1;
	for(int i = 18; i >= 0; i --)
		if(tmp>>i&1) x = f[x][i];
	return x;
}
inline void add(int rt, int x, int w) {
	if(rt == x) update(1, 1, n, 1, n, w);
	else if(isAncestor(rt, x)) update(1, 1, n, in[x], out[x], w);
	else {
		int y = find(rt, x);
		update(1, 1, n, 1, in[y]-1, w);
		update(1, 1, n, out[y]+1, n, w);
	}
}
inline ll qry(int rt, int x) {
	if(rt == x) return sum[1];
	else if(isAncestor(rt, x)) return query(1, 1, n, in[x], out[x]);
	else {
		int y = find(rt, x);
		return query(1, 1, n, 1, in[y]-1) + query(1, 1, n, out[y]+1, n);
	}
}
int main() {
	n = read(), m = read();
	for(int i = 1; i <= n; i ++) a[i] = read();
	for(int i = 1; i < n; i ++) {
		int x = read(), y = read();
		addedge(x, y); addedge(y, x);
	}
	rt = 1;
	dfs(1, 0, 0); build(1, 1, n);
	for(int j = 1; j <= 18; j ++)
		for(int i = 1; i <= n; i ++) f[i][j] = f[f[i][j-1]][j-1];
	while(m --) {
		int opt = read(), x, y, z, w;
		if(opt == 1) rt = read();
		else if(opt == 2) {
			x = read(), y = read(), w = read();
			z = getlca(rt, x, y);
			add(rt, z, w);
		} else {
			x = read();
			write(qry(rt, x)); puts("");
		}
	}
	return 0;
}


#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<cctype>
#define lc (o<<1)
#define rc (o<<1|1)
using namespace std;
typedef long long ll;

inline ll read() {
	char ch = getchar(); ll x = 0; int op = 1;
	for(; !isdigit(ch); ch = getchar()) if(ch == '-') op = -1;
	for(; isdigit(ch); ch = getchar()) x = x*10+ch-'0';
	return x*op;
}
inline void write(ll a) {
	if(a < 0) putchar('-'), a = -a;
	if(a >= 10) write(a/10); putchar('0'+a%10);
}

const int N = 200010;
int n, m, cnt, clk, rt;
int a[N], val[N], head[N], depth[N], f[N][25], in[N], out[N];
ll sum[N<<2], tag[N<<2];
struct edge {
	int to, nxt;
	edge() {}
	edge(int x, int y) { to = x, nxt = y; }
}e[N<<1];

//segment tree
inline void build(int o, int l, int r) {
	if(l == r) { sum[o] = val[l]; return; }
	int mid = l+r>>1;
	build(lc, l, mid); build(rc, mid+1, r);
	sum[o] = sum[lc]+sum[rc];
}
inline void pushdown(int o, int l, int r) {
	if(!tag[o]) return;
	tag[lc] += tag[o]; tag[rc] += tag[o];
	int mid = l+r>>1;
	sum[lc] += (ll)tag[o]*(mid-l+1); sum[rc] += (ll)tag[o]*(r-mid);
	tag[o] = 0;
}
inline void update(int o, int l, int r, int x, int y, int w) {
	if(l == x && r == y) {
		sum[o] += (ll)(r-l+1)*w; tag[o] += w; return;
	}
	pushdown(o, l, r);
	int mid = l+r>>1;
	if(y <= mid) update(lc, l, mid, x, y, w);
	else if(x > mid) update(rc, mid+1, r, x, y, w);
	else update(lc, l, mid, x, mid, w), update(rc, mid+1, r, mid+1, y, w);
	sum[o] = sum[lc]+sum[rc];
}
inline ll query(int o, int l, int r, int x, int y) {
	if(l == x && r == y) return sum[o];
	pushdown(o, l, r);
	ll ret = 0; int mid = l+r>>1;
	if(y <= mid) return query(lc, l, mid, x, y);
	else if(x > mid) return query(rc, mid+1, r, x, y);
	else return query(lc, l, mid, x, mid) + query(rc, mid+1, r, mid+1, y);
}

inline void addedge(int x, int y) { e[++ cnt] = edge(y, head[x]); head[x] = cnt; }
inline bool isAncestor(int x, int y) { return in[x] <= in[y] && out[x] >= out[y]; }
inline void dfs(int u, int lst, int s) {
	depth[u] = s; f[u][0] = lst; in[u] = ++ clk; val[clk] = a[u];
	for(int i = head[u]; i; i = e[i].nxt) if(e[i].to != lst) dfs(e[i].to, u, s+1);
	out[u] = clk;
}
inline int lca(int x, int y) {
	if(depth[x] < depth[y]) swap(x, y);
	int tmp = depth[x]-depth[y];
	for(int i = 20; i >= 0; i --)
		if(tmp>>i&1) x = f[x][i];
	if(x == y) return x;
	for(int i = 20; i >= 0; i --)
		if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
	return f[x][0];
}
inline int getlca(int rt, int x, int y) {
	int u = lca(x, rt), v = lca(y, rt), w = lca(x, y);
	return u^v^w;
}
inline int find(int x, int y) {
	int tmp = depth[x]-depth[y]-1;
	for(int i = 20; i >= 0; i --)
		if(tmp>>i&1) x = f[x][i];
	return x;
}
inline void add(int rt, int x, int w) {
	if(rt == x) update(1, 1, n, 1, n, w);
	else if(!isAncestor(x, rt)) update(1, 1, n, in[x], out[x], w);
	else {
		int y = find(rt, x);
		update(1, 1, n, 1, in[y]-1, w);
		update(1, 1, n, out[y]+1, n, w);
	}
}
inline ll qry(int rt, int x) {
	if(rt == x) return sum[1];
	else if(!isAncestor(x, rt)) return query(1, 1, n, in[x], out[x]);
	else {
		int y = find(rt, x);
		return query(1, 1, n, 1, in[y]-1) + query(1, 1, n, out[y]+1, n);
	}
}
int main() {
	n = read(), m = read();
	for(int i = 1; i <= n; i ++) a[i] = read();
	for(int i = 1; i < n; i ++) {
		int x = read(), y = read();
		addedge(x, y); addedge(y, x);
	}
	rt = 1;
	dfs(1, 0, 0); build(1, 1, n);
	for(int j = 1; j <= 20; j ++)
		for(int i = 1; i <= n; i ++) f[i][j] = f[f[i][j-1]][j-1];
	while(m --) {
		int opt = read(), x, y, z, w;
		if(opt == 1) rt = read();
		else if(opt == 2) {
			x = read(), y = read(), w = read();
			z = getlca(rt, x, y);
			add(rt, z, w);
		} else {
			x = read();
			write(qry(rt, x)); puts("");
		}
	}
	return 0;
}


#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<cctype>
#define lc (o<<1)
#define rc (o<<1|1)
using namespace std;
typedef long long ll;

inline ll read() {
	char ch = getchar(); ll x = 0; int op = 1;
	for(; !isdigit(ch); ch = getchar()) if(ch == '-') op = -1;
	for(; isdigit(ch); ch = getchar()) x = x*10+ch-'0';
	return x*op;
}
inline void write(ll a) {
	if(a < 0) putchar('-'), a = -a;
	if(a >= 10) write(a/10); putchar('0'+a%10);
}

const int N = 200010;
int n, m, cnt, clk, rt;
int a[N], val[N], head[N], depth[N], f[N][25], in[N], out[N];
ll sum[N<<2], tag[N<<2];
struct edge {
	int to, nxt;
	edge() {}
	edge(int x, int y) { to = x, nxt = y; }
}e[N<<1];

//segment tree
inline void build(int o, int l, int r) {
	if(l == r) { sum[o] = val[l]; return; }
	int mid = l+r>>1;
	build(lc, l, mid); build(rc, mid+1, r);
	sum[o] = sum[lc]+sum[rc];
}
inline void pushdown(int o, int l, int r) {
	if(!tag[o]) return;
	tag[lc] += tag[o]; tag[rc] += tag[o];
	int mid = l+r>>1;
	sum[lc] += (ll)tag[o]*(mid-l+1); sum[rc] += (ll)tag[o]*(r-mid);
	tag[o] = 0;
}
inline void update(int o, int l, int r, int x, int y, int w) {
	if(l == x && r == y) {
		sum[o] += (ll)(r-l+1)*w; tag[o] += w; return;
	}
	pushdown(o, l, r);
	int mid = l+r>>1;
	if(y <= mid) update(lc, l, mid, x, y, w);
	else if(x > mid) update(rc, mid+1, r, x, y, w);
	else update(lc, l, mid, x, mid, w), update(rc, mid+1, r, mid+1, y, w);
	sum[o] = sum[lc]+sum[rc];
}
inline ll query(int o, int l, int r, int x, int y) {
	if(l == x && r == y) return sum[o];
	pushdown(o, l, r);
	ll ret = 0; int mid = l+r>>1;
	if(y <= mid) return query(lc, l, mid, x, y);
	else if(x > mid) return query(rc, mid+1, r, x, y);
	else return query(lc, l, mid, x, mid) + query(rc, mid+1, r, mid+1, y);
}

inline void addedge(int x, int y) { e[++ cnt] = edge(y, head[x]); head[x] = cnt; }
inline bool isAncestor(int x, int y) { return in[x] <= in[y] && out[x] >= out[y]; }
inline void dfs(int u, int lst, int s) {
	depth[u] = s; f[u][0] = lst; in[u] = ++ clk; val[clk] = a[u];
	for(int i = head[u]; i; i = e[i].nxt) if(e[i].to != lst) dfs(e[i].to, u, s+1);
	out[u] = clk;
}
inline int lca(int x, int y) {
	if(depth[x] < depth[y]) swap(x, y);
	int tmp = depth[x]-depth[y];
	for(int i = 20; i >= 0; i --)
		if(tmp>>i&1) x = f[x][i];
	if(x == y) return x;
	for(int i = 20; i >= 0; i --)
		if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
	return f[x][0];
}
inline int getlca(int rt, int x, int y) {
	if(isAncestor(rt, x) && isAncestor(rt, y)) return lca(x, y);
	else if(isAncestor(rt, x) || isAncestor(rt, y)) return rt;
	int u = lca(x, rt), v = lca(y, rt);
	if(depth[u] > depth[v]) return u; else return v;
}
inline int find(int x, int y) {
	int tmp = depth[x]-depth[y]-1;
	for(int i = 20; i >= 0; i --)
		if(tmp>>i&1) x = f[x][i];
	return x;
}
inline void add(int rt, int x, int w) {
	if(rt == x) update(1, 1, n, 1, n, w);
	else if(isAncestor(rt, x)) update(1, 1, n, in[x], out[x], w);
	else {
		int y = find(rt, x);
		update(1, 1, n, 1, in[y]-1, w);
		update(1, 1, n, out[y]+1, n, w);
	}
}
inline ll qry(int rt, int x) {
	if(rt == x) return sum[1];
	else if(!isAncestor(x, rt)) return query(1, 1, n, in[x], out[x]);
	else {
		int y = find(rt, x);
		return query(1, 1, n, 1, in[y]-1) + query(1, 1, n, out[y]+1, n);
	}
}
int main() {
	n = read(), m = read();
	for(int i = 1; i <= n; i ++) a[i] = read();
	for(int i = 1; i < n; i ++) {
		int x = read(), y = read();
		addedge(x, y); addedge(y, x);
	}
	rt = 1;
	dfs(1, 0, 0); build(1, 1, n);
	for(int j = 1; j <= 20; j ++)
		for(int i = 1; i <= n; i ++) f[i][j] = f[f[i][j-1]][j-1];
	while(m --) {
		int opt = read(), x, y, z, w;
		if(opt == 1) rt = read();
		else if(opt == 2) {
			x = read(), y = read(), w = read();
			z = getlca(rt, x, y);
			add(rt, z, w);
		} else {
			x = read();
			write(qry(rt, x)); puts("");
		}
	}
	return 0;
}


#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<cctype>
#define lc (o<<1)
#define rc (o<<1|1)
using namespace std;
typedef long long ll;

inline ll read() {
	char ch = getchar(); ll x = 0; int op = 1;
	for(; !isdigit(ch); ch = getchar()) if(ch == '-') op = -1;
	for(; isdigit(ch); ch = getchar()) x = x*10+ch-'0';
	return x*op;
}
inline void write(ll a) {
	if(a < 0) putchar('-'), a = -a;
	if(a >= 10) write(a/10); putchar('0'+a%10);
}

const int N = 200010;
int n, m, cnt, clk, rt;
int a[N], val[N], head[N], depth[N], f[N][20], in[N], out[N];
ll sum[N<<2], tag[N<<2];
struct edge {
	int to, nxt;
	edge() {}
	edge(int x, int y) { to = x, nxt = y; }
}e[N<<1];

//segment tree
inline void build(int o, int l, int r) {
	if(l == r) { sum[o] = val[l]; return; }
	int mid = l+r>>1;
	build(lc, l, mid); build(rc, mid+1, r);
	sum[o] = sum[lc]+sum[rc];
}
inline void pushdown(int o, int l, int r) {
	if(!tag[o]) return;
	tag[lc] += tag[o]; tag[rc] += tag[o];
	int mid = l+r>>1;
	sum[lc] += (ll)tag[o]*(mid-l+1); sum[rc] += (ll)tag[o]*(r-mid);
	tag[o] = 0;
}
inline void update(int o, int l, int r, int x, int y, int w) {
	if(l == x && r == y) {
		sum[o] += (ll)(r-l+1)*w; tag[o] += w; return;
	}
	pushdown(o, l, r);
	int mid = l+r>>1;
	if(y <= mid) update(lc, l, mid, x, y, w);
	else if(x > mid) update(rc, mid+1, r, x, y, w);
	else update(lc, l, mid, x, mid, w), update(rc, mid+1, r, mid+1, y, w);
	sum[o] = sum[lc]+sum[rc];
}
inline ll query(int o, int l, int r, int x, int y) {
	if(l == x && r == y) return sum[o];
	pushdown(o, l, r);
	ll ret = 0; int mid = l+r>>1;
	if(y <= mid) return query(lc, l, mid, x, y);
	else if(x > mid) return query(rc, mid+1, r, x, y);
	else return query(lc, l, mid, x, mid) + query(rc, mid+1, r, mid+1, y);
}

inline void addedge(int x, int y) { e[++ cnt] = edge(y, head[x]); head[x] = cnt; }
inline bool isAncestor(int x, int y) { return in[x] <= in[y] && out[x] >= out[y]; }
inline void dfs(int u, int lst, int s) {
	depth[u] = s; f[u][0] = lst; in[u] = ++ clk; val[clk] = a[u];
	for(int i = head[u]; i; i = e[i].nxt) if(e[i].to != lst) dfs(e[i].to, u, s+1);
	out[u] = clk;
}
inline int lca(int x, int y) {
	if(depth[x] < depth[y]) swap(x, y);
	int tmp = depth[x]-depth[y];
	for(int i = 18; i >= 0; i --)
		if(tmp>>i&1) x = f[x][i];
	if(x == y) return x;
	for(int i = 18; i >= 0; i --)
		if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
	return f[x][0];
}
inline int getlca(int rt, int x, int y) {
	if(isAncestor(rt, x) && isAncestor(rt, y)) return lca(x, y);
	else if(isAncestor(rt, x) || isAncestor(rt, y)) return rt;
	int u = lca(x, rt), v = lca(y, rt);
	if(depth[u] > depth[v]) return u; else return v;
}
inline int find(int x, int y) {
	int tmp = depth[x]-depth[y]-1;
	for(int i = 18; i >= 0; i --)
		if(tmp>>i&1) x = f[x][i];
	return x;
}
inline void add(int rt, int x, int w) {
	if(rt == x) update(1, 1, n, 1, n, w);
	else if(isAncestor(rt, x)) update(1, 1, n, in[x], out[x], w);
	else {
		int y = find(rt, x);
		update(1, 1, n, 1, in[y]-1, w);
		update(1, 1, n, out[y]+1, n, w);
	}
}
inline ll qry(int rt, int x) {
	if(rt == x) return sum[1];
	else if(isAncestor(rt, x)) return query(1, 1, n, in[x], out[x]);
	else {
		int y = find(rt, x);
		return query(1, 1, n, 1, in[y]-1) + query(1, 1, n, out[y]+1, n);
	}
}
int main() {
	n = read(), m = read();
	for(int i = 1; i <= n; i ++) a[i] = read();
	for(int i = 1; i < n; i ++) {
		int x = read(), y = read();
		addedge(x, y); addedge(y, x);
	}
	rt = 1;
	dfs(1, 0, 0); build(1, 1, n);
	for(int j = 1; j <= 18; j ++)
		for(int i = 1; i <= n; i ++) f[i][j] = f[f[i][j-1]][j-1];
	while(m --) {
		int opt = read(), x, y, z, w;
		if(opt == 1) rt = read();
		else if(opt == 2) {
			x = read(), y = read(), w = read();
			z = getlca(rt, x, y);
			add(rt, z, w);
		} else {
			x = read();
			write(qry(rt, x)); puts("");
		}
	}
	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();
			int t1 = LCA(v, root), t2 = LCA(u, root), t3 = LCA(u, v);
			if (dep[t1] > dep[t2]) lca = t1; else lca = t2;
			if (dep[t3] > dep[lca]) lca = t3;
			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, 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)) lca = root;
				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 (contain(u, root)) lca = u;
			else if (contain(v, root)) lca = v;
			else
			{
				int t1 = LCA(root, u), t2 = LCA(u, v);
				if (dep[t1] > dep[t2]) lca = t1;
				else lca = t2;
			}
			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()
{
	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 (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 if (contain(root, u) || contain(root, v)) lca = root;
			else
			{
				lca = LCA(u, v);
				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;
}
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)) ans = sum[1] - find(1, 1, n, in[u], out[u]);
	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))
	{
		if (in[u] != 1) change(1, 1, n, 1, in[u] - 1, x);
		if (out[u] != n) change(1, 1, n, out[u] + 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()
{
	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);
			modify(lca, x);
		}
		if (opt == 3)
		{
			int v;
			v = read();
			solve(v);
		}
	}
	return 0;
}