#include<bits/stdc++.h>
#define FOR(i,n) for(i=0;i<n;i++)
#define FORI(i,n,inc) for(i=0;i<n;i+=inc)
std::string ap="\n";
#define ap endl
#define VI vector<int>
#define PII pair<int,int>
#define PLL pair<int,int>
#define MII map<int,int>
#define MSI map<string,int>
#define UMII unordered_map<int,int>
using LL=long long int;
using ULL=unsigned long long int;
using LD=long double;
#define sync ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define ALL(x) (x).begin(), (x).end()
using namespace std;
struct custom_hash {
    static uint64_t splitmix64(uint64_t x) {
        // http://xorshift.di.unimi.it/splitmix64.c
        x += 0x9e3779b97f4a7c15;
        x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
        x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
        return x ^ (x >> 31);
    }

    size_t operator()(uint64_t x) const {
        static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count();
        return splitmix64(x + FIXED_RANDOM);
    }
};

#ifdef sharp
#define DEBUG(x) cout<<#x<<": "<<x<<endl
#endif

int i,j,l,m;

int main()
{
	sync;
	int t,n,k;
	cin>>n>>k;
	vector<int>vec(k);
	l=ceil(n/float(2));
	while(n--)
	{
		cin>>t;
		vec[t-1]++;
	}
	sort(vec.begin(),vec.end(),greater<int>());
	int ans;
	for(int i=0;i<vec.size();i++){
		if(l-ceil(vec[i]/float(2))<0)
		{
			ans+=min(l*2,vec[i]);break;
		}
		l-=ceil(vec[i]/float(2));
		ans+=vec[i];
		if(l==0)break;
	}
	cout<<ans<<endl;
	return 0;
}


#include<bits/stdc++.h>
#define FOR(i,n) for(i=0;i<n;i++)
#define FORI(i,n,inc) for(i=0;i<n;i+=inc)
std::string ap="\n";
#define ap endl
#define VI vector<int>
#define PII pair<int,int>
#define PLL pair<int,int>
#define MII map<int,int>
#define MSI map<string,int>
#define UMII unordered_map<int,int>
using LL=long long int;
using ULL=unsigned long long int;
using LD=long double;
#define sync ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define ALL(x) (x).begin(), (x).end()
using namespace std;
struct custom_hash {
    static uint64_t splitmix64(uint64_t x) {
        // http://xorshift.di.unimi.it/splitmix64.c
        x += 0x9e3779b97f4a7c15;
        x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
        x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
        return x ^ (x >> 31);
    }

    size_t operator()(uint64_t x) const {
        static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count();
        return splitmix64(x + FIXED_RANDOM);
    }
};

#ifdef sharp
#define DEBUG(x) cout<<#x<<": "<<x<<endl
#endif

int i,j,l,m;

int main()
{
	sync;
	int t,n,k;
	cin>>n>>k;
	vector<int>vec(k);
	l=ceil(n/float(2));
	while(n--)
	{
		cin>>t;
		vec[t-1]++;
	}
	sort(vec.begin(),vec.end(),greater<int>());
	int ans=0;
	for(int i=0;i<vec.size();i++){
		if(l-ceil(vec[i]/float(2))<0)
		{
			ans+=min(l*2,vec[i]);break;
		}
		l-=ceil(vec[i]/float(2));
		ans+=vec[i];
		if(l==0)break;
	}
	cout<<ans<<endl;
	return 0;
}


#include<bits/stdc++.h>
#define FOR(i,n) for(i=0;i<n;i++)
#define FORI(i,n,inc) for(i=0;i<n;i+=inc)
std::string ap="\n";
#define ap endl
#define VI vector<int>
#define PII pair<int,int>
#define PLL pair<int,int>
#define MII map<int,int>
#define MSI map<string,int>
#define UMII unordered_map<int,int>
using LL=long long int;
using ULL=unsigned long long int;
using LD=long double;
#define sync ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define ALL(x) (x).begin(), (x).end()
using namespace std;
struct custom_hash {
    static uint64_t splitmix64(uint64_t x) {
        // http://xorshift.di.unimi.it/splitmix64.c
        x += 0x9e3779b97f4a7c15;
        x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
        x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
        return x ^ (x >> 31);
    }

    size_t operator()(uint64_t x) const {
        static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count();
        return splitmix64(x + FIXED_RANDOM);
    }
};

#ifdef sharp
#define DEBUG(x) cout<<#x<<": "<<x<<endl
#endif

int main()
{
	sync;
	int t,n,k,l=0;
	cin>>n>>k;
	vector<int>vec(k);
	l=ceil(n/float(2));
	while(n--)
	{
		cin>>t;
		vec[t-1]++;
	}
	sort(vec.begin(),vec.end(),greater<int>());
	int ans=0;
	for(int i=0;i<vec.size();i++)
	{
		ans+=vec[i]/2*2;
		l-=vec[i]/2;
	}
	if(l>0)ans+=l;
	cout<<ans<<endl;
	return 0;
}


#include<bits/stdc++.h>
#define FOR(i,n) for(i=0;i<n;i++)
#define FORI(i,n,inc) for(i=0;i<n;i+=inc)
std::string ap="\n";
#define ap endl
#define VI vector<int>
#define PII pair<int,int>
#define PLL pair<int,int>
#define MII map<int,int>
#define MSI map<string,int>
#define UMII unordered_map<int,int>
using LL=long long int;
using ULL=unsigned long long int;
using LD=long double;
#define sync ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define ALL(x) (x).begin(), (x).end()
using namespace std;
struct custom_hash {
    static uint64_t splitmix64(uint64_t x) {
        // http://xorshift.di.unimi.it/splitmix64.c
        x += 0x9e3779b97f4a7c15;
        x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
        x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
        return x ^ (x >> 31);
    }

    size_t operator()(uint64_t x) const {
        static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count();
        return splitmix64(x + FIXED_RANDOM);
    }
};

#ifdef sharp
#define DEBUG(x) cout<<#x<<": "<<x<<endl
#endif

int i,j,l,m;

int main()
{
	sync;
	int t,n,k;
	cin>>n>>k;
	vector<int>vec(k);
	l=ceil(n/float(2));
	while(n--)
	{
		cin>>t;
		vec[t-1]++;
	}
	sort(vec.begin(),vec.end(),greater<int>());
	int ans;
	for(int i=0;i<vec.size();i++){
		if(l-ceil(vec[i]/float(2))<=0)
		{
			ans+=min(l*2,vec[i]);break;
		}
		l-=ceil(vec[i]/float(2));
		ans+=vec[i];
	}
	cout<<ans<<endl;
	return 0;
}


#include<bits/stdc++.h>
#define FOR(i,n) for(i=0;i<n;i++)
#define FORI(i,n,inc) for(i=0;i<n;i+=inc)
std::string ap="\n";
#define ap endl
#define VI vector<int>
#define PII pair<int,int>
#define PLL pair<int,int>
#define MII map<int,int>
#define MSI map<string,int>
#define UMII unordered_map<int,int>
using LL=long long int;
using ULL=unsigned long long int;
using LD=long double;
#define sync ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define ALL(x) (x).begin(), (x).end()
using namespace std;
struct custom_hash {
    static uint64_t splitmix64(uint64_t x) {
        // http://xorshift.di.unimi.it/splitmix64.c
        x += 0x9e3779b97f4a7c15;
        x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
        x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
        return x ^ (x >> 31);
    }

    size_t operator()(uint64_t x) const {
        static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count();
        return splitmix64(x + FIXED_RANDOM);
    }
};

#ifdef sharp
#define DEBUG(x) cout<<#x<<": "<<x<<endl
#endif

int main()
{
	sync;
	int t,n,k,l=0;
	cin>>n>>k;
	vector<int>vec(k);
	l=ceil(n/float(2));
	while(n--)
	{
		cin>>t;
		vec[t-1]++;
	}
	sort(vec.begin(),vec.end(),greater<int>());
	int ans=0;
	for(int i=0;i<vec.size();i++){
		if((l-int(ceil(vec[i]/float(2))))<0)
		{
			ans+=min(l*2,vec[i]);break;
		}
		l-=int(ceil(vec[i]/float(2)));
		ans+=vec[i];
		if(l==0)break;
	}
	cout<<ans<<endl;
	return 0;
}


#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <algorithm>
#include <map>
#include <iomanip>
#include <set>

#define ll long long
#define pb push_back
//#define f first
//#define s second
#define mp make_pair
#define fi(i, a, b) for (int i = a; i < b; i++)
#define watch(x) cout << (#x) << " is " << x << endl;

using namespace std;

const int mod = 1e9 + 7;

int form(int n, int k, int a) {
    int ans = ((1 + n - a) * (n - a)) / 2 - a;
    return ans - k;
}

int main() {
    int n, k;
    cin >> n >> k;
    vector<int> a(k + 1);
    int ans = 0;
    for (int i = 0; i < n; i++) {
        int temp;
        cin >> temp;
        a[temp]++;
        if (a[temp] == 2) {
            ans += 2;
            a[temp] = 0;
        }
    }

    int c = (n + 1) / 2 - ans + 1 / 2;
    //int num = min(c, ost);

    cout << ans + c << endl;

    return 0;
}


#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <algorithm>
#include <map>
#include <iomanip>
#include <set>

#define ll long long
#define pb push_back
//#define f first
//#define s second
#define mp make_pair
#define fi(i, a, b) for (int i = a; i < b; i++)
#define watch(x) cout << (#x) << " is " << x << endl;

using namespace std;

const int mod = 1e9 + 7;

int form(int n, int k, int a) {
    int ans = ((1 + n - a) * (n - a)) / 2 - a;
    return ans - k;
}

int main() {
    int n, k;
    cin >> n >> k;
    vector<int> a(k + 1);
    int ans = 0;
    for (int i = 0; i < n; i++) {
        int temp;
        cin >> temp;
        a[temp]++;
        if (a[temp] == 2) {
            ans += 2;
            a[temp] = 0;
        }
    }

    int c = count(a.begin(), a.end(), 1);
    int ost = min(n - ans, c);
    //int num = min(c, ost);

    cout << ans + ost << endl;

    return 0;
}


#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <algorithm>
#include <map>
#include <iomanip>
#include <set>

#define ll long long
#define pb push_back
//#define f first
//#define s second
#define mp make_pair
#define fi(i, a, b) for (int i = a; i < b; i++)
#define watch(x) cout << (#x) << " is " << x << endl;

using namespace std;

const int mod = 1e9 + 7;

int form(int n, int k, int a) {
    int ans = ((1 + n - a) * (n - a)) / 2 - a;
    return ans - k;
}

int main() {
    int n, k;
    cin >> n >> k;
    vector<int> a(n + 1);
    int ans = 0;
    for (int i = 0; i < n; i++) {
        int temp;
        cin >> temp;
        a[temp]++;
        if (a[temp] == 2) {
            ans += 2;
            a[temp] = 0;
        }
    }

    //int c = count(a.begin(), a.end(), 1);
    int ost = ((n - ans + 1) / 2);
    //int num = min(c, ost);

    cout << ans + ost << endl;

    return 0;
}


#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <algorithm>
#include <map>
#include <iomanip>
#include <set>

#define ll long long
#define pb push_back
//#define f first
//#define s second
#define mp make_pair
#define fi(i, a, b) for (int i = a; i < b; i++)
#define watch(x) cout << (#x) << " is " << x << endl;

using namespace std;

const int mod = 1e9 + 7;

int main() {
    int n, k;
    cin >> n >> k;
    vector <int> a(n + 1);
    vector<pair<int, int>> j(k + 1);
    for (int i = 1; i <= n; i ++) {
        int temp;
        cin >> temp;
        j[temp].first++;
        j[temp].second = temp;
    }

    sort(j.rbegin(), j.rend());
    int ans = 0;
    int count = 0;
    int num = (n + 1) / 2;
    for (auto e : j) {
        int tempc = (e.first + 1) / 2;
        if (count + tempc > num) {
            if (tempc > 0) {
                ans += (num - count) * 2;
            }
            break;
        }
        count += tempc;
        ans += e.first;
    }

    cout << ans << endl;

    return 0;
}


#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <algorithm>
#include <map>
#include <iomanip>
#include <set>

#define ll long long
#define pb push_back
//#define f first
//#define s second
#define mp make_pair
#define fi(i, a, b) for (int i = a; i < b; i++)
#define watch(x) cout << (#x) << " is " << x << endl;

using namespace std;

const int mod = 1e9 + 7;

int form(int n, int k, int a) {
    int ans = ((1 + n - a) * (n - a)) / 2 - a;
    return ans - k;
}

int main() {
    int n, k;
    cin >> n >> k;
    vector<int> a(k + 1);
    int ans = 0;
    for (int i = 0; i < n; i++) {
        int temp;
        cin >> temp;
        a[temp]++;
        if (a[temp] == 2) {
            ans += 2;
            a[temp] = 0;
        }
    }

    //int c = count(a.begin(), a.end(), 1);
    int ost = ((n - ans + 1) / 2);
    //int num = min(c, ost);

    cout << ans + ost << endl;

    return 0;
}


#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <algorithm>
#include <map>
#include <iomanip>
#include <set>

#define ll long long
#define pb push_back
//#define f first
//#define s second
#define mp make_pair
#define fi(i, a, b) for (int i = a; i < b; i++)
#define watch(x) cout << (#x) << " is " << x << endl;

using namespace std;

const int mod = 1e9 + 7;

int form(int n, int k, int a) {
    int ans = ((1 + n - a) * (n - a)) / 2 - a;
    return ans - k;
}

int main() {
    int n, k;
    cin >> n >> k;
    vector <int> a(n + 1);
    vector<pair<int, int>> j(k + 1);
    for (int i = 1; i <= n; i ++) {
        int temp;
        cin >> temp;
        j[temp].first++;
        j[temp].second = temp;
    }

    sort(j.rbegin(), j.rend());
    int ans = 0;
    int count = 0;
    int num = (n + 1) / 2;
    for (auto e : j) {
        int tempc = (e.first + 1) / 2;
        if (count + tempc > num) {
            ans += min(n - ans, (num - count) * 2);
            break;
        }
        count += tempc;
        ans += e.first;
    }

    cout << ans << endl;

    return 0;
}


#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <algorithm>
#include <map>
#include <iomanip>
#include <set>

#define ll long long
#define pb push_back
//#define f first
//#define s second
#define mp make_pair
#define fi(i, a, b) for (int i = a; i < b; i++)
#define watch(x) cout << (#x) << " is " << x << endl;

using namespace std;

const int mod = 1e9 + 7;

int form(int n, int k, int a) {
    int ans = ((1 + n - a) * (n - a)) / 2 - a;
    return ans - k;
}

int main() {
    int n, k;
    cin >> n >> k;
    vector<int> a(k + 1);
    int ans = 0;
    for (int i = 0; i < n; i++) {
        int temp;
        cin >> temp;
        a[temp]++;
        if (a[temp] == 2) {
            ans += 2;
            a[temp] = 0;
        }
    }

    int c = (n + 1) / 2 - (ans + 1) / 2;
    //int num = min(c, ost);

    cout << ans + c << endl;

    return 0;
}


#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <algorithm>
#include <map>
#include <iomanip>
#include <set>

#define ll long long
#define pb push_back
//#define f first
//#define s second
#define mp make_pair
#define fi(i, a, b) for (int i = a; i < b; i++)
#define watch(x) cout << (#x) << " is " << x << endl;

using namespace std;

const int mod = 1e9 + 7;

int form(int n, int k, int a) {
    int ans = ((1 + n - a) * (n - a)) / 2 - a;
    return ans - k;
}

int main() {
    int n, k;
    cin >> n >> k;
    vector<int> a(k + 1);
    int ans = 0;
    for (int i = 0; i < n; i++) {
        int temp;
        cin >> temp;
        a[temp]++;
        if (a[temp] == 2) {
            ans += 2;
            a[temp] = 0;
        }
    }

    int c = count(a.begin(), a.end(), 1);
    //int ost = min(n - ans, c);
    //int num = min(c, ost);

    cout << ans + c << endl;

    return 0;
}


#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <algorithm>
#include <map>
#include <iomanip>
#include <set>

#define ll long long
#define pb push_back
//#define f first
//#define s second
#define mp make_pair
#define fi(i, a, b) for (int i = a; i < b; i++)
#define watch(x) cout << (#x) << " is " << x << endl;

using namespace std;

const int mod = 1e9 + 7;

int form(int n, int k, int a) {
    int ans = ((1 + n - a) * (n - a)) / 2 - a;
    return ans - k;
}

int main() {
    int n, k;
    cin >> n >> k;
    vector <int> a(n + 1);
    vector<pair<int, int>> j(k + 1);
    for (int i = 1; i <= n; i ++) {
        int temp;
        cin >> temp;
        j[temp].first++;
        j[temp].second = temp;
    }

    sort(j.rbegin(), j.rend());
    int ans = 0;
    int count = 0;
    int num = (n + 1) / 2;
    for (auto e : j) {
        int tempc = (e.first + 1) / 2;
        if (count + tempc > num) {
            if (tempc > 0) {
                ans += min(n - ans, (num - count) * 2);
            }
            break;
        }
        count += tempc;
        ans += e.first;
    }

    cout << ans << endl;

    return 0;
}


#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
    int n,k;
    cin>>n>>k;
    int x=n/2;
    int y=0,d=0,r=0,ans=0;
    if(n%2!=0) x++;
    int arr[n+1];
    int cnt[k+1];
    for(int i=1;i<=k;i++) cnt[i]=0;
    ///for(int i=0;i<=k+1;i++) cout<<cnt[i]<<" ";
    ///cout<<endl;
    for(int i=0;i<n;i++){
        cin>>arr[i];
        cnt[arr[i]]++;
    }
    sort(cnt+1,cnt+(k+1));
    ///for(int i=1;i<=k;i++) cout<<cnt[i]<<" ";
    ///cout<<endl;
    for(int i=k;i>0;i--){
        d+=(cnt[i]/2);
        if(cnt[i]%2!=0) r++;
    }
    ans+=(min(x,d)*2);
    x-=(min(x,d));
    ans+=(min(x,r));
    cout<<ans<<endl;
    return 0;
}


#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
    int n,k;
    cin>>n>>k;
    int x=n/2,y=0,z=0,ans=0;
    if(n%2!=0) x++;
    int arr[n+1];
    int cnt[n+1]={0};
    for(int i=0;i<n;i++) cin>>arr[i];
    for(int i=0;i<n;i++){
        cnt[arr[i]]++;
    }
    sort(cnt,cnt+n);
    for(int i=n-1;i>=0;i--){
        if(cnt[i]==0 || x<=0) break;
        y=(cnt[i]/2);
        if(y>=x){
            ans+=(y*2);
            break;
        }
        z=(y*2);
        if(cnt[i]%2!=0){
            y++;
            z++;
        }
        ans+=z;
        x-=y;
    }
    cout<<ans<<endl;
    return 0;
}


#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
    int n,k;
    cin>>n>>k;
    int x=n/2,y=0,z=0,ans=0;
    if(n%2!=0) x++;
    int arr[n+1];
    int cnt[k+1]={0};
    for(int i=0;i<n;i++) cin>>arr[i];
    for(int i=0;i<n;i++){
        cnt[arr[i]]++;
    }
    sort(cnt,cnt+k);
    for(int i=k;i>=0;i--){
        if(cnt[i]==0 || x<=0) break;
        y=(cnt[i]/2);
        if(y>=x){
            ans+=(y*2);
            break;
        }
        z=(y*2);
        if(cnt[i]%2!=0){
            y++;
            z++;
        }
        ans+=z;
        x-=y;
    }
    cout<<ans<<endl;
    return 0;
}


#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
    int n,k;
    cin>>n>>k;
    int x=n/2;
    int y=0,z=0,ans=0;
    if(n%2!=0) x++;
    int arr[n+1];
    int cnt[k+1]={0};
    for(int i=0;i<n;i++) cin>>arr[i];
    for(int i=0;i<n;i++){
        cnt[arr[i]]++;
    }
    sort(cnt,cnt+(k+1));
    for(int i=k;i>=0;i--){
        if(cnt[i]==0 || x<=0) break;
        y=(cnt[i]/2);
        if(y>=x){
            ans+=(x*2);
            break;
        }
        z=(y*2);
        if(cnt[i]%2!=0){
            y++;
            z++;
        }
        ans+=z;
        x-=y;
    }
    cout<<ans<<endl;
    return 0;
}


#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
    int n,k;
    cin>>n>>k;
    int x=n/2;
    int y=0,z=0,ans=0;
    if(n%2!=0) x++;
    int arr[n+1];
    int cnt[k+2];
    for(int i=1;i<=k;i++) cnt[i]=0;
    ///for(int i=0;i<=k+1;i++) cout<<cnt[i]<<" ";
    ///cout<<endl;
    for(int i=0;i<n;i++) cin>>arr[i];
    for(int i=0;i<n;i++){
        cnt[arr[i]]++;
    }
    sort(cnt+1,cnt+(k+1));
    ///for(int i=1;i<=k;i++) cout<<cnt[i]<<" ";
    ///cout<<endl;
    for(int i=k;i>0;i--){
        if(cnt[i]==0 || x<=0) break;
        y=(cnt[i]/2);
        if(y>=x){
            ans+=(x*2);
            break;
        }
        z=(y*2);
        if(cnt[i]%2!=0){
            y++;
            z++;
        }
        ans+=z;
        x-=y;
    }
    cout<<ans<<endl;
    return 0;
}


#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll a[100005];
ll b[100005];

ll sum(ll a[],ll n)
{
    ll s=0;
    for(ll i=0;i<n;i++)
    {s+=a[i];}
    return s;
}

void input(ll a[],ll n)
{
    for(int i=0;i<n;i++)
    cin>>a[i];
}

int main(void){
  ll n,k;
  cin>>n>>k;
  input(a,n);
  int freq[1001]={0};
  for(int i=0;i<n;i++)
  {
      freq[a[i]]++;
  }
  sort(freq,freq+n);
  int c=0;
  for(int i=n-1;i>=0;i--)
  {
      if(freq[i]%2)
      c++;
  }
  cout<<n-c/2;
}


#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll a[100005];
ll b[100005];

ll sum(ll a[],ll n)
{
    ll s=0;
    for(ll i=0;i<n;i++)
    {s+=a[i];}
    return s;
}

void input(ll a[],ll n)
{
    for(int i=0;i<n;i++)
    cin>>a[i];
}

int main(void){
  ll n,k;
  cin>>n>>k;
  input(a,n);
  int freq[1001]={0};
  for(int i=0;i<n;i++)
  {
      freq[a[i]]++;
  }
  sort(freq,freq+n);
  int c=0;
  for(int i=n;i>=0;i--)
  {
      if(freq[i]%2)
      {
          c++;
      }
  }
  cout<<n-c/2;
}


#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll a[100005];
ll b[100005];

ll sum(ll a[],ll n)
{
    ll s=0;
    for(ll i=0;i<n;i++)
    {s+=a[i];}
    return s;
}

void input(ll a[],ll n)
{
    for(int i=0;i<n;i++)
    cin>>a[i];
}

int main(void){
  ll n,k;
  cin>>n>>k;
  input(a,n);
  int freq[1001]={0};
  for(int i=0;i<n;i++)
  {
      freq[a[i]]++;
  }

  int c=0;
  for(int i=k;i>=0;i--)
  {
      if(freq[i]%2)
      {
          c++;
      }
  }
 // cout<<c<<endl;

  cout<<n-(c)/2;
}


#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll a[100005];
ll b[100005];

ll sum(ll a[],ll n)
{
    ll s=0;
    for(ll i=0;i<n;i++)
    {s+=a[i];}
    return s;
}

void input(ll a[],ll n)
{
    for(int i=0;i<n;i++)
    cin>>a[i];
}

int main(void){
  ll n,k;
  cin>>n>>k;
  input(a,n);
  int freq[1001]={0};
  for(int i=0;i<n;i++)
  {
      freq[a[i]]++;
  }
  sort(freq,freq+n);
  int c=0;
  for(int i=k;i>=0;i--)
  {
      if(freq[i]%2)
      {
          c++;
      }
  }
  cout<<n-c/2;
}


#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll a[100005];
ll b[100005];

ll sum(ll a[],ll n)
{
    ll s=0;
    for(ll i=0;i<n;i++)
    {s+=a[i];}
    return s;
}

void input(ll a[],ll n)
{
    for(int i=0;i<n;i++)
    cin>>a[i];
}

int main(void){
  ll n,k;
  cin>>n>>k;
  input(a,n);
  int freq[1001]={0};
  for(int i=0;i<n;i++)
  {
      freq[a[i]]++;
  }
  sort(freq,freq+n);
  int c=0;
  for(int i=n-1;i>=0;i--)
  {
      if(freq[i]%2 && i>0)
      {freq[i-1]-=1;
          c++;
      }
  }
  cout<<n-c;
}


#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;
int a[1000];
int main(){
	int n, k ;
	cin>>n>>k;
	for(int i = 1; i <=n; i++){
		int t;
		cin>>t;
		a[t]++;
	}
	int res = 0, count;
	if (n%2==1){
		count = n/2 + 1;
	}else{
		count = n/2;
	}
	for(int i = 1; i <= n; i++){
		if (count<=0)
			break;
		if (a[i]/2>0){
			count = count - (a[i]/2);
			res += (a[i]/2)*2;
			a[i] = 1;
		}
	}
	for(int i = 0; i <= n; i++){
		if (count<=0)
			break;
		if (a[i]!=0){
			res++;
			count--;
		}
	}
	cout<<res;
    return 0;
}


import java.util.*;
import java.io.*;
public class Main {
    void solve(){
        int n=ni(),q=ni();
        graph=new ArrayList[n+1];
        for(int i=1;i<=n;i++) graph[i]=new ArrayList<>();
        b=new long[n+1];
        for(int i=1;i<=n;i++) b[i]=nl();
        for(int i=1;i<n;i++){
            int x=ni(),y=ni();
            graph[x].add(y);
            graph[y].add(x);
        }
        tin=new int[n+1];
        tout=new int[n+1];
        a=new long[n+1];
        tree=new long[4*n+1];
        lazy=new long[4*n+1];
        st=new  int[n+1];
        ed=new int[n+1];
        MAXL=log2(n);
        P=new int[n+1][MAXL+1];
        parent=new int[n+1];
        level=new int[n+1];

        dfs(1,-1,0);
        for(int i=1;i<=n;i++) a[st[i]]=b[i];
        build(1,1,n);
        precompute(n);

        while(q-->0){
            int t=ni();
            if(t==1){
                root=ni();
            }else if(t==2){
                int u=ni(),v=ni();
                long x=nl();
                querry1(u,v,x,n);
                for(int i=1;i<=n;i++){
                  //  pw.println(querry(1,i,i,1,n));
                }
            }else {
                int v=ni();
                long ans=querry2(v,n);
                pw.println(ans);
            }

        }

    }
    int root=1;
    long b[];
    ArrayList<Integer> graph[];
    int tin[];
    int tout[];
    long a[];
    long tree[];
    long lazy[];
    int st[];
    int ed[];
    int P[][];
    int parent[];
    int level[];
    int MAXL;
    int cc=0,cc2=0;
    void querry1(int u,int v,long x,int n){
        int l1=lca(u,v),l2=lca(u,root),l3=lca(v,root);
        int depth=0,lca=-1;
        if(level[l1]>=depth){
            depth=level[l1];
            lca=l1;
        }
        if(level[l2]>=depth){
            depth=level[l2];
            lca=l2;
        }
        if(level[l3]>=depth){
            depth=level[l3];
            lca=l3;
        }
        if(root==lca){
            update(1,1,n,1,n,x);
        }else
        if(tin[root]<=tin[lca] && tout[root]>=tout[lca]){
             update(1,st[lca],ed[lca],1,n,x);
        }else {
            if(tin[lca]<=tin[root] && tout[lca]>=tout[root]){
                update(1,1,n,1,n,x);
                int ch=-1;
                for(int child : graph[lca]){
                     if(child!=parent[lca]){
                         if(tin[child]<=tin[root] && tout[child]>=tout[root]){
                             ch=child;
                             break;
                         }
                     }
                }
                update(1,st[ch],ed[ch],1,n,-x);
            }else {
                update(1,st[lca],ed[lca],1,n,x);
            }
        }
    }
    long querry2(int v,int n){
          if(root==v){
              return querry(1,1,n,1,n);
          }else
          if(tin[root]<=tin[v] && tout[root]>=tout[v]){
              return querry(1,st[v],ed[v],1,n);
          }else {
              if(tin[v]<=tin[root] && tout[v]>=tout[root]){
                  long ans=querry(1,1,n,1,n);

                  int ch=-1;
                  for(int child : graph[v]){
                      if(child!=parent[v]){
                          if(tin[child]<=tin[root] && tout[child]>=tout[root]){
                              ch=child;
                              break;
                          }
                      }
                  }
                  ans-=querry(1,st[ch],ed[ch],1,n);
                  return ans;
              }else {
                  return querry(1,st[v],ed[v],1,n);
              }
          }
    }

    void dfs(int v,int pr,int l){
        tin[v]=++cc;
        st[v]=++cc2;
        level[v]=l;
        parent[v]=pr;
        for(int u  : graph[v]){
             if(u!=pr) dfs(u,v,l+1);
        }
        tout[v]=++cc;
        ed[v]=cc2;
    }
    void build(int id,int l,int r){
        if(l==r){
            tree[id]=a[l];
        }else {
            int mid=(l+r)/2;
            build(2*id,l,mid);
            build(2*id+1,mid+1,r);
            tree[id]=tree[2*id]+tree[2*id+1];
        }
    }
    void update(int id,int x,int y,int l,int r,long val){
        if(lazy[id]!=0){
            tree[id]+=lazy[id]*(r-l+1);
            if(l!=r){
                lazy[2*id]+=lazy[id];
                lazy[2*id+1]+=lazy[id];

            }
            lazy[id]=0;
        }
        if(r<x || l>y) return;
        if(x<=l && r<=y){
            tree[id]+=(r-l+1)*val;
            if(l!=r){
                lazy[2*id]+=val;
                lazy[2*id+1]+=val;
            }
            return;
        }
        int mid=(l+r)/2;
        update(2*id,x,y,l,mid,val);
        update(2*id+1,x,y,mid+1,r,val);
        tree[id]=tree[2*id]+tree[2*id+1];
    }
    long querry(int id,int x,int y,int l,int r){
        if(lazy[id]!=0){
            tree[id]+=lazy[id]*(r-l+1);
            if(l!=r){
                lazy[2*id]+=lazy[id];
                lazy[2*id+1]+=lazy[id];

            }
            lazy[id]=0;
        }
        if(r<x || l>y) return 0;
        if(x<=l && r<=y) return tree[id];
        int mid=(l+r)/2;
        return querry(2*id,x,y,l,mid)+querry(2*id+1,x,y,mid+1,r);
    }

    void precompute(int n){
        for(int i=1;i<=n;i++){
            for(int j=0;(1<<j)<n;j++) P[i][j]=-1;

        }
        for(int i=1;i<=n;i++) P[i][0]=parent[i];
        for(int j=1;(1<<j)<n;j++){
             for(int i=1;i<=n;i++){
                 if(P[i][j-1]!=-1)
                 P[i][j]=P[P[i][j-1]][j-1];
             }
        }
    }
    static int log2(int v){
        return (int)(Math.log10(v)/Math.log10(2));
    }
     int lca(int u ,int v){
        if(level[u]<level[v]){
            int t=u;
            u=v;
            v=t;
        }
        int dist=level[u]-level[v];
        while(dist>0){
            int raise_by=log2(dist);
            u=P[u][raise_by];
            dist-=(1<<raise_by);
        }
        if(u==v) return u;
        for(int j=MAXL;j>=0;j--){
            if(P[u][j]!=-1 && P[u][j]!=P[v][j]){
                u=P[u][j];
                v=P[v][j];
            }
        }
        return parent[u];

    }

    long M=(long)1e9+7;
    InputStream is;
    PrintWriter pw;
    String INPUT = "";
    void run() throws Exception {
        is = INPUT.isEmpty() ? System.in : new ByteArrayInputStream(INPUT.getBytes());
        pw = new PrintWriter(System.out);
        long s = System.currentTimeMillis();
        solve();
        pw.flush();
        if(!INPUT.isEmpty())tr(System.currentTimeMillis()-s+"ms");
    }

    public static void main(String[] args) throws Exception { new Main().run(); }

    private byte[] inbuf = new byte[1024];
    public int lenbuf = 0, ptrbuf = 0;

    private int readByte() {
        if(lenbuf == -1)throw new InputMismatchException();
        if(ptrbuf >= lenbuf){
            ptrbuf = 0;
            try { lenbuf = is.read(inbuf); } catch (IOException e) { throw new InputMismatchException(); }
            if(lenbuf <= 0)return -1;
        }
        return inbuf[ptrbuf++];
    }

    private boolean isSpaceChar(int c) { return !(c >= 33 && c <= 126); }
    private int skip() { int b; while((b = readByte()) != -1 && isSpaceChar(b)); return b; }

    private double nd() { return Double.parseDouble(ns()); }
    private char nc() { return (char)skip(); }

    private String ns() {
        int b = skip();
        StringBuilder sb = new StringBuilder();
        while(!(isSpaceChar(b))){ // when nextLine, (isSpaceChar(b) && b != ' ')
            sb.appendCodePoint(b);
            b = readByte();
        }
        return sb.toString();
    }

    private char[] ns(int n) {
        char[] buf = new char[n];
        int b = skip(), p = 0;
        while(p < n && !(isSpaceChar(b))){
            buf[p++] = (char)b;
            b = readByte();
        }
        return n == p ? buf : Arrays.copyOf(buf, p);
    }

    private char[][] nm(int n, int m) {
        char[][] map = new char[n][];
        for(int i = 0;i < n;i++)map[i] = ns(m);
        return map;
    }

    private int[] na(int n) {
        int[] a = new int[n];
        for(int i = 0;i < n;i++)a[i] = ni();
        return a;
    }

    private int ni() {
        int num = 0, b;
        boolean minus = false;
        while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
        if(b == '-'){
            minus = true;
            b = readByte();
        }

        while(true){
            if(b >= '0' && b <= '9'){
                num = num * 10 + (b - '0');
            }else{
                return minus ? -num : num;
            }
            b = readByte();
        }
    }

    private long nl() {
        long num = 0;
        int b;
        boolean minus = false;
        while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
        if(b == '-'){
            minus = true;
            b = readByte();
        }

        while(true){
            if(b >= '0' && b <= '9'){
                num = num * 10 + (b - '0');
            }else{
                return minus ? -num : num;
            }
            b = readByte();
        }
    }

    private void tr(Object... o) { if(INPUT.length() > 0)System.out.println(Arrays.deepToString(o)); }
}


import java.util.*;
import java.io.*;
public class Main {
    void solve(){
        int n=ni(),q=ni();
        int from[]=new int[n-1];
        int to[]=new int[n-1];
        b=new long[n+1];
        for(int i=1;i<=n;i++) b[i]=nl();
        for(int i=1;i<n;i++){
            int x=ni(),y=ni();
            from[i-1]=x; to[i-1]=y;
        }
        graph=packU(n,from,to);
        tin=new int[n+1];
        tout=new int[n+1];
        a=new long[n+1];
        tree=new long[4*n+1];
        lazy=new long[4*n+1];
        st=new  int[n+1];
        ed=new int[n+1];
        MAXL=log2(n);
        P=new int[n+1][MAXL+1];
        parent=new int[n+1];
        level=new int[n+1];

        dfs(1,-1,0);
        for(int i=1;i<=n;i++) a[st[i]]=b[i];
        build(1,1,n);
        precompute(n);

        while(q-->0){
            int t=ni();
            if(t==1){
                root=ni();
            }else if(t==2){
                int u=ni(),v=ni();
                long x=nl();
                querry1(u,v,x,n);

            }else {
                int v=ni();
                long ans=querry2(v,n);
                pw.println(ans);
            }

        }

    }
    ////// for undirected graph
    static int[][] packU(int n, int[] from, int[] to) {
        int[][] g = new int[n+1][];
        int[] p = new int[n+1];
        for (int f : from)
            p[f]++;
        for (int t : to)
            p[t]++;
        for (int i = 1; i <= n; i++)
            g[i] = new int[p[i]];
        for (int i = 0; i < from.length; i++) {
            g[from[i]][--p[from[i]]] = to[i];
            g[to[i]][--p[to[i]]] = from[i];
        }
        return g;
    }
    int root=1;
    long b[];
    int graph[][];
    int tin[];
    int tout[];
    long a[];
    long tree[];
    long lazy[];
    int st[];
    int ed[];
    int P[][];
    int parent[];
    int level[];
    int MAXL;
    int cc=0,cc2=0;
    void querry1(int u,int v,long x,int n){
        int l1=lca(u,v),l2=lca(u,root),l3=lca(v,root);
        int depth=0,lca=-1;
        if(level[l1]>=depth){
            depth=level[l1];
            lca=l1;
        }
        if(level[l2]>=depth){
            depth=level[l2];
            lca=l2;
        }
        if(level[l3]>=depth){
            depth=level[l3];
            lca=l3;
        }
        if(root==lca){
            update(1,1,n,1,n,x);
        }else
        if(tin[root]<=tin[lca] && tout[root]>=tout[lca]){
             update(1,st[lca],ed[lca],1,n,x);
        }else {
            if(tin[lca]<=tin[root] && tout[lca]>=tout[root]){
                update(1,1,n,1,n,x);
                int ch=-1;
                for(int child : graph[lca]){
                     if(child!=parent[lca]){
                         if(tin[child]<=tin[root] && tout[child]>=tout[root]){
                             ch=child;
                             break;
                         }
                     }
                }
                update(1,st[ch],ed[ch],1,n,-x);
            }else {
                update(1,st[lca],ed[lca],1,n,x);
            }
        }
    }
    long querry2(int v,int n){
          if(root==v){
              return querry(1,1,n,1,n);
          }else
          if(tin[root]<=tin[v] && tout[root]>=tout[v]){
              return querry(1,st[v],ed[v],1,n);
          }else {
              if(tin[v]<=tin[root] && tout[v]>=tout[root]){
                  long ans=querry(1,1,n,1,n);

                  int ch=-1;
                  for(int child : graph[v]){
                      if(child!=parent[v]){
                          if(tin[child]<=tin[root] && tout[child]>=tout[root]){
                              ch=child;
                              break;
                          }
                      }
                  }
                  ans-=querry(1,st[ch],ed[ch],1,n);
                  return ans;
              }else {
                  return querry(1,st[v],ed[v],1,n);
              }
          }
    }

    void dfs(int v,int pr,int l){
        tin[v]=++cc;
        st[v]=++cc2;
        level[v]=l;
        parent[v]=pr;
        for(int u  : graph[v]){
             if(u!=pr) dfs(u,v,l+1);
        }
        tout[v]=++cc;
        ed[v]=cc2;
    }
    void build(int id,int l,int r){
        if(l==r){
            tree[id]=a[l];
        }else {
            int mid=(l+r)/2;
            build(2*id,l,mid);
            build(2*id+1,mid+1,r);
            tree[id]=tree[2*id]+tree[2*id+1];
        }
    }
    void update(int id,int x,int y,int l,int r,long val){
        if(lazy[id]!=0){
            tree[id]+=lazy[id]*(r-l+1);
            if(l!=r){
                lazy[2*id]+=lazy[id];
                lazy[2*id+1]+=lazy[id];

            }
            lazy[id]=0;
        }
        if(r<x || l>y) return;
        if(x<=l && r<=y){
            tree[id]+=(r-l+1)*val;
            if(l!=r){
                lazy[2*id]+=val;
                lazy[2*id+1]+=val;
            }
            return;
        }
        int mid=(l+r)/2;
        update(2*id,x,y,l,mid,val);
        update(2*id+1,x,y,mid+1,r,val);
        tree[id]=tree[2*id]+tree[2*id+1];
    }
    long querry(int id,int x,int y,int l,int r){
        if(lazy[id]!=0){
            tree[id]+=lazy[id]*(r-l+1);
            if(l!=r){
                lazy[2*id]+=lazy[id];
                lazy[2*id+1]+=lazy[id];

            }
            lazy[id]=0;
        }
        if(r<x || l>y) return 0;
        if(x<=l && r<=y) return tree[id];
        int mid=(l+r)/2;
        return querry(2*id,x,y,l,mid)+querry(2*id+1,x,y,mid+1,r);
    }

    void precompute(int n){
        for(int i=1;i<=n;i++){
            for(int j=0;(1<<j)<n;j++) P[i][j]=-1;

        }
        for(int i=1;i<=n;i++) P[i][0]=parent[i];
        for(int j=1;(1<<j)<n;j++){
             for(int i=1;i<=n;i++){
                 if(P[i][j-1]!=-1)
                 P[i][j]=P[P[i][j-1]][j-1];
             }
        }
    }
    static int log2(int v){
        return (int)(Math.log10(v)/Math.log10(2));
    }
     int lca(int u ,int v){
        if(level[u]<level[v]){
            int t=u;
            u=v;
            v=t;
        }
        int dist=level[u]-level[v];
        while(dist>0){
            int raise_by=log2(dist);
            u=P[u][raise_by];
            dist-=(1<<raise_by);
        }
        if(u==v) return u;
        for(int j=MAXL;j>=0;j--){
            if(P[u][j]!=-1 && P[u][j]!=P[v][j]){
                u=P[u][j];
                v=P[v][j];
            }
        }
        return parent[u];

    }

    long M=(long)1e9+7;
    InputStream is;
    PrintWriter pw;
    String INPUT = "";
    void run() throws Exception {
        is = INPUT.isEmpty() ? System.in : new ByteArrayInputStream(INPUT.getBytes());
        pw = new PrintWriter(System.out);
        long s = System.currentTimeMillis();
        solve();
        pw.flush();
        if(!INPUT.isEmpty())tr(System.currentTimeMillis()-s+"ms");
    }

    public static void main(String[] args) throws Exception { new Main().run(); }

    private byte[] inbuf = new byte[1024];
    public int lenbuf = 0, ptrbuf = 0;

    private int readByte() {
        if(lenbuf == -1)throw new InputMismatchException();
        if(ptrbuf >= lenbuf){
            ptrbuf = 0;
            try { lenbuf = is.read(inbuf); } catch (IOException e) { throw new InputMismatchException(); }
            if(lenbuf <= 0)return -1;
        }
        return inbuf[ptrbuf++];
    }

    private boolean isSpaceChar(int c) { return !(c >= 33 && c <= 126); }
    private int skip() { int b; while((b = readByte()) != -1 && isSpaceChar(b)); return b; }

    private double nd() { return Double.parseDouble(ns()); }
    private char nc() { return (char)skip(); }

    private String ns() {
        int b = skip();
        StringBuilder sb = new StringBuilder();
        while(!(isSpaceChar(b))){ // when nextLine, (isSpaceChar(b) && b != ' ')
            sb.appendCodePoint(b);
            b = readByte();
        }
        return sb.toString();
    }

    private char[] ns(int n) {
        char[] buf = new char[n];
        int b = skip(), p = 0;
        while(p < n && !(isSpaceChar(b))){
            buf[p++] = (char)b;
            b = readByte();
        }
        return n == p ? buf : Arrays.copyOf(buf, p);
    }

    private char[][] nm(int n, int m) {
        char[][] map = new char[n][];
        for(int i = 0;i < n;i++)map[i] = ns(m);
        return map;
    }

    private int[] na(int n) {
        int[] a = new int[n];
        for(int i = 0;i < n;i++)a[i] = ni();
        return a;
    }

    private int ni() {
        int num = 0, b;
        boolean minus = false;
        while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
        if(b == '-'){
            minus = true;
            b = readByte();
        }

        while(true){
            if(b >= '0' && b <= '9'){
                num = num * 10 + (b - '0');
            }else{
                return minus ? -num : num;
            }
            b = readByte();
        }
    }

    private long nl() {
        long num = 0;
        int b;
        boolean minus = false;
        while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
        if(b == '-'){
            minus = true;
            b = readByte();
        }

        while(true){
            if(b >= '0' && b <= '9'){
                num = num * 10 + (b - '0');
            }else{
                return minus ? -num : num;
            }
            b = readByte();
        }
    }

    private void tr(Object... o) { if(INPUT.length() > 0)System.out.println(Arrays.deepToString(o)); }
}


#include <bits/stdc++.h>
using namespace std;

#define FOR(i, a, b) for (int i = (a), _b = (b); i <= _b; ++i)
#define FORd(i, a, b) for (int i = (a), _b = (b); i >= _b; --i)
#define FORall(it, a) for (__typeof((a).begin()) it = (a).begin(); it != (a).end(); ++it)
#define ms(x, n) memset(x, n, sizeof(x))
#define sz(x) int((x).size())
#define all(x) (x).begin(), (x).end()
#define uni(x) (x).erase(unique(all(x)), (x).end())
#define prec(x) fixed << setprecision((x))
#define fi first
#define se second
#define pb push_back
#define pf push_front
#define mp make_pair
#define long long long
#define db(x) cerr << #x << " = " << (x) << ", ";
#define endln cerr << "\n";
#define chkpt cerr << "------\n";
template<class T> inline int chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }
template<class T> inline int chkmin(T &a, T b) { return a > b ? a = b, 1 : 0; }
typedef pair<int, int> pi;
const int INF = (int) 1e9;
const long LINF = (long) 1e18;
#define LL(x) (2 * (x))
#define RR(x) (2 * (x) + 1)

const int maxn = 100000 + 15;
const int logn = 20;

int n, q;
int a[maxn];
vector<int> g[maxn];
long st[4 * maxn], lz[4 * maxn];
int in[maxn], out[maxn], tme, lev[maxn];
int par[maxn][logn];
int root;

#define mid ((l + r) >> 1)
void lazy(int node, int l, int r) {
    st[node] += 1LL * (r - l + 1) * lz[node];
    if (l != r) {
        lz[LL(node)] += lz[node];
        lz[RR(node)] += lz[node];
    }
    lz[node] = 0;
}

void upd(int node, int l, int r, int L, int R, long val) {
    lazy(node, l, r);
    if (r < L || l > R) return;
    if (L <= l && r <= R) {
        lz[node] += val;
        lazy(node, l, r);
        return;
    }
    upd(LL(node), l, mid, L, R, val);
    upd(RR(node), mid + 1, r, L, R, val);
    st[node] = st[LL(node)] + st[RR(node)];
}

long query(int node, int l, int r, int L, int R) {
    lazy(node, l, r);
    if (r < L || l > R) return 0;
    if (L <= l && r <= R) return st[node];
    return query(LL(node), l, mid, L, R) + query(RR(node), mid + 1, r, L, R);
}
#undef mid

void dfs(int u, int p, int d) {
    in[u] = ++tme;
    lev[u] = d;
    FOR(i, 0, sz(g[u]) - 1) {
        int v = g[u][i];
        if (v == p) continue;
        par[v][0] = u;
        dfs(v, u, d + 1);
    }
    out[u] = tme;
}

void changeRoot(int u) {
    root = u;
}

void buildLCA() {
    changeRoot(1);
    ms(par, -1);
    tme = 0;
    dfs(1, 1, 1);
    FOR(j, 1, logn - 1) FOR(i, 1, n) if (~par[i][j - 1])
        par[i][j] = par[par[i][j - 1]][j - 1];
}

int fakeLCA(int u, int v) {
    if (lev[u] < lev[v]) return fakeLCA(v, u);
    FORd(i, logn - 1, 0) {
        if (~par[u][i] && lev[u] - (1 << i) >= lev[v]) {
            u = par[u][i];
        }
    }
    if (u == v) return u;
    FORd(i, logn - 1, 0) {
        if (~par[u][i] && par[u][i] != par[v][i]) {
            u = par[u][i];
            v = par[v][i];
        }
    }
    return par[u][0];
}

int bit(int x, int i) {
    return (x >> i) & 1;
}

int kthAncestor(int u, int k) {
    FORd(i, 31, 0) if (bit(k, i)) {
        u = par[u][i];
    }
    return u;
}

int isAncestor(int u, int v) {
    return in[u] < in[v] && out[v] <= out[u];
}

int lca(int u, int v) {
    int w1 = fakeLCA(u, root);
    int w2 = fakeLCA(v, root);
    int w3 = fakeLCA(u, v);
    int mx = max(lev[w1], max(lev[w2], lev[w3]));
    if (mx == lev[w1]) return w1;
    if (mx == lev[w2]) return w2;
    return w3;
}

int nearestAncestor(int u, int v) {
    int k = lev[v] - lev[u] - 1;
    return kthAncestor(v, k);
}

void upd(int u, int v, int x) {
    int w = lca(u, v);
    if (isAncestor(w, root)) {
        int ww = nearestAncestor(w, root);
        upd(1, 1, n, 1, n, x);
        upd(1, 1, n, in[ww], out[ww], -x);
    } else {
        if (w == root) {
            upd(1, 1, n, 1, n, x);
        } else {
            upd(1, 1, n, in[w], out[w], x);
        }
    }
}

long query(int u) {
    if (isAncestor(u, root)) {
        int uu = nearestAncestor(u, root);
        return query(1, 1, n, 1, n) - query(1, 1, n, in[uu], out[uu]);
    }
    if (u == root) {
        return query(1, 1, n, 1, n);
    }
    return query(1, 1, n, in[u], out[u]);
}

int main() {
//    freopen("916E.INP", "r", stdin);
    ios_base::sync_with_stdio(0); cin.tie(0);
    cin >> n >> q;
    FOR(i, 1, n) cin >> a[i];
    FOR(i, 1, n - 1) {
        int u, v; cin >> u >> v;
        g[u].pb(v);
        g[v].pb(u);
    }
    buildLCA();
    FOR(i, 1, n) {
        upd(1, 1, n, in[i], in[i], a[i]);
    }
    while (q--) {
        int cmd; cin >> cmd;
        if (cmd == 1) {
            int u; cin >> u;
            changeRoot(u);
        } else if (cmd == 2) {
            int u, v, x; cin >> u >> v >> x;
            upd(u, v, x);
        } else {
            int u; cin >> u;
            cout << query(u) << '\n';
        }
    }
    return 0;
}


#include <bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
	int k=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){k=k*10+ch-'0';ch=getchar();}
	return k*f;
}
inline void write(int x){
	if(x<0)putchar('-'),x=-x;
	if(x>9)write(x/10);putchar(x%10+'0');
}
inline void writeln(int x){
	write(x);puts("");
}
int nedge=0,p[200010],nex[200010],head[200010];
int n,q,a[100010],f[100010][18],deep[100010],sx[100010],xs[100010],cnt=0,s[100010];
inline void addedge(int a,int b){
	p[++nedge]=b;nex[nedge]=head[a];head[a]=nedge;
}
inline void dfs(int x,int dep){
	deep[x]=dep;sx[x]=++cnt;xs[cnt]=x;s[x]=1;
	for(int k=head[x];k;k=nex[k])if(p[k]!=f[x][0]){
		f[p[k]][0]=x;dfs(p[k],dep+1);
		s[x]+=s[p[k]];
	}
}
inline int up(int x,int dep){
	for(int i=17;i>=0;i--)if(deep[f[x][i]]>=dep)x=f[x][i];
	return x;
}
inline int lca(int x,int y){
	if(deep[x]<deep[y])swap(x,y);
	x=up(x,deep[y]);
	for(int i=17;i>=0;i--)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
	if(x!=y)x=f[x][0];return x;
}
int t[400010],lt[400010],rt[400010],add[400010];
inline void build(int l,int r,int nod){
	lt[nod]=l;rt[nod]=r;add[nod]=0;
	if(l==r){t[nod]=a[xs[l]];return;}
	int mid=l+r>>1;
	build(l,mid,nod*2);build(mid+1,r,nod*2+1);
	t[nod]=t[nod*2]+t[nod*2+1];
}
inline void pushdown(int nod){
	if(!add[nod])return;
	if(lt[nod]!=rt[nod]){
		t[nod*2]+=(rt[nod*2]-lt[nod*2]+1)*add[nod];
		t[nod*2+1]+=(rt[nod*2+1]-lt[nod*2+1]+1)*add[nod];
		add[nod*2]+=add[nod];add[nod*2+1]+=add[nod];
	}add[nod]=0;
}
inline void xg(int i,int j,int v,int nod){
	pushdown(nod);
	if(lt[nod]>=i&&rt[nod]<=j){
		t[nod]+=(rt[nod]-lt[nod]+1)*v;add[nod]+=v;
		return;
	}
	int mid=lt[nod]+rt[nod]>>1;
	if(i<=mid)xg(i,j,v,nod*2);
	if(j>mid)xg(i,j,v,nod*2+1);
	t[nod]=t[nod*2]+t[nod*2+1];
}
inline int ssum(int i,int j,int nod){
	pushdown(nod);
	if(lt[nod]>=i&&rt[nod]<=j)return t[nod];
	int mid=lt[nod]+rt[nod]>>1,ans=0;
	if(i<=mid)ans+=ssum(i,j,nod*2);
	if(j>mid)ans+=ssum(i,j,nod*2+1);
	return ans;
}
signed main()
{
	n=read();q=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);
	}
	dfs(1,1);
	for(int j=1;j<18;j++)
		for(int i=1;i<=n;i++)f[i][j]=f[f[i][j-1]][j-1];
	build(1,n,1);int Rt=1;
	while(q--){
		int op=read();
		if(op==1)Rt=read();
		if(op==2){
			int x=read(),y=read(),v=read();int LCA;
			if(lca(lca(x,y),Rt)!=lca(x,y))LCA=lca(x,y);
			else{
				int X=lca(Rt,x),Y=lca(Rt,y);
				LCA=(deep[X]>deep[Y])?X:Y;
			}
			if(LCA==Rt)xg(1,n,v,1);
			else if(lca(LCA,Rt)!=LCA)xg(sx[LCA],sx[LCA]+s[LCA]-1,v,1);
			else{
				xg(1,n,v,1);int k=up(Rt,deep[LCA]+1);
				xg(sx[k],sx[k]+s[k]-1,-v,1);
			}
		}
		if(op==3){
			int x=read();
			if(x==Rt)writeln(ssum(1,n,1));
			else if(lca(x,Rt)!=x)writeln(ssum(sx[x],sx[x]+s[x]-1,1));
			else{
				int ans=ssum(1,n,1);int k=up(Rt,deep[x]+1);
				ans-=ssum(sx[k],sx[k]+s[k]-1,1);
				writeln(ans);
			}
		}
	}
	return 0;
}


#include <bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
	int k=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){k=k*10+ch-'0';ch=getchar();}
	return k*f;
}
inline void write(int x){
	if(x<0)putchar('-'),x=-x;
	if(x>9)write(x/10);putchar(x%10+'0');
}
inline void writeln(int x){
	write(x);puts("");
}
int nedge=0,p[200010],nex[200010],head[200010];
int n,q,a[100010],f[100010][18],deep[100010],sx[100010],xs[100010],cnt=0,s[100010];
inline void addedge(int a,int b){
	p[++nedge]=b;nex[nedge]=head[a];head[a]=nedge;
}
inline void dfs(int x,int dep){
	deep[x]=dep;sx[x]=++cnt;xs[cnt]=x;s[x]=1;
	for(int k=head[x];k;k=nex[k])if(p[k]!=f[x][0]){
		f[p[k]][0]=x;dfs(p[k],dep+1);
		s[x]+=s[p[k]];
	}
}
inline int up(int x,int dep){
	for(int i=17;i>=0;i--)if(deep[f[x][i]]>=dep)x=f[x][i];
	return x;
}
inline int lca(int x,int y){
	if(deep[x]<deep[y])swap(x,y);
	x=up(x,deep[y]);
	for(int i=17;i>=0;i--)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
	if(x!=y)x=f[x][0];return x;
}
int t[400010],lt[400010],rt[400010],add[400010];
inline void build(int l,int r,int nod){
	lt[nod]=l;rt[nod]=r;add[nod]=0;
	if(l==r){t[nod]=a[xs[l]];return;}
	int mid=l+r>>1;
	build(l,mid,nod*2);build(mid+1,r,nod*2+1);
	t[nod]=t[nod*2]+t[nod*2+1];
}
inline void pushdown(int nod){
	if(!add[nod])return;
	if(lt[nod]!=rt[nod]){
		t[nod*2]+=(rt[nod*2]-lt[nod*2]+1)*add[nod];
		t[nod*2+1]+=(rt[nod*2+1]-lt[nod*2+1]+1)*add[nod];
		add[nod*2]+=add[nod];add[nod*2+1]+=add[nod];
	}add[nod]=0;
}
inline void xg(int i,int j,int v,int nod){
	pushdown(nod);
	if(lt[nod]>=i&&rt[nod]<=j){
		t[nod]+=(rt[nod]-lt[nod]+1)*v;add[nod]+=v;
		return;
	}
	int mid=lt[nod]+rt[nod]>>1;
	if(i<=mid)xg(i,j,v,nod*2);
	if(j>mid)xg(i,j,v,nod*2+1);
	t[nod]=t[nod*2]+t[nod*2+1];
}
inline int ssum(int i,int j,int nod){
	pushdown(nod);
	if(lt[nod]>=i&&rt[nod]<=j)return t[nod];
	int mid=lt[nod]+rt[nod]>>1,ans=0;
	if(i<=mid)ans+=ssum(i,j,nod*2);
	if(j>mid)ans+=ssum(i,j,nod*2+1);
	return ans;
}
signed main()
{
	n=read();q=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);
	}
	dfs(1,1);
	for(int j=1;j<18;j++)
		for(int i=1;i<=n;i++)f[i][j]=f[f[i][j-1]][j-1];
	build(1,n,1);int Rt=1;
	while(q--){
		int op=read();
		if(op==1)Rt=read();
		if(op==2){
			int x=read(),y=read(),v=read();int LCA;
			if(lca(lca(x,y),Rt)==Rt)LCA=lca(x,y);
			else{
				int X=lca(Rt,x),Y=lca(Rt,y);
				LCA=(deep[X]>deep[Y])?X:Y;
			}
			if(LCA==Rt)xg(1,n,v,1);
			else if(lca(LCA,Rt)!=LCA)xg(sx[LCA],sx[LCA]+s[LCA]-1,v,1);
			else{
				xg(1,n,v,1);int k=up(Rt,deep[LCA]+1);
				xg(sx[k],sx[k]+s[k]-1,-v,1);
			}
		}
		if(op==3){
			int x=read();
			if(x==Rt)writeln(ssum(1,n,1));
			else if(lca(x,Rt)!=x)writeln(ssum(sx[x],sx[x]+s[x]-1,1));
			else{
				int ans=ssum(1,n,1);int k=up(Rt,deep[x]+1);
				ans-=ssum(sx[k],sx[k]+s[k]-1,1);
				writeln(ans);
			}
		}
	}
	return 0;
}


#include <bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
	int k=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){k=k*10+ch-'0';ch=getchar();}
	return k*f;
}
inline void write(int x){
	if(x<0)putchar('-'),x=-x;
	if(x>9)write(x/10);putchar(x%10+'0');
}
inline void writeln(int x){
	write(x);puts("");
}
int nedge=0,p[200010],nex[200010],head[200010];
int n,q,a[100010],f[100010][18],deep[100010],sx[100010],xs[100010],cnt=0,s[100010];
inline void addedge(int a,int b){
	p[++nedge]=b;nex[nedge]=head[a];head[a]=nedge;
}
inline void dfs(int x,int dep){
	deep[x]=dep;sx[x]=++cnt;xs[cnt]=x;s[x]=1;
	for(int k=head[x];k;k=nex[k])if(p[k]!=f[x][0]){
		f[p[k]][0]=x;dfs(p[k],dep+1);
		s[x]+=s[p[k]];
	}
}
inline int up(int x,int dep){
	for(int i=17;i>=0;i--)if(deep[f[x][i]]>=dep)x=f[x][i];
	return x;
}
inline int lca(int x,int y){
	if(deep[x]<deep[y])swap(x,y);
	x=up(x,deep[y]);
	for(int i=17;i>=0;i--)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
	if(x!=y)x=f[x][0];return x;
}
int t[400010],lt[400010],rt[400010],add[400010];
inline void build(int l,int r,int nod){
	lt[nod]=l;rt[nod]=r;add[nod]=0;
	if(l==r){t[nod]=a[xs[l]];return;}
	int mid=l+r>>1;
	build(l,mid,nod*2);build(mid+1,r,nod*2+1);
	t[nod]=t[nod*2]+t[nod*2+1];
}
inline void pushdown(int nod){
	if(!add[nod])return;
	if(lt[nod]!=rt[nod]){
		t[nod*2]+=(rt[nod*2]-lt[nod*2]+1)*add[nod];
		t[nod*2+1]+=(rt[nod*2+1]-lt[nod*2+1]+1)*add[nod];
		add[nod*2]+=add[nod];add[nod*2+1]+=add[nod];
	}add[nod]=0;
}
inline void xg(int i,int j,int v,int nod){
	pushdown(nod);
	if(lt[nod]>=i&&rt[nod]<=j){
		t[nod]+=(rt[nod]-lt[nod]+1)*v;add[nod]+=v;
		return;
	}
	int mid=lt[nod]+rt[nod]>>1;
	if(i<=mid)xg(i,j,v,nod*2);
	if(j>mid)xg(i,j,v,nod*2+1);
	t[nod]=t[nod*2]+t[nod*2+1];
}
inline int ssum(int i,int j,int nod){
	pushdown(nod);
	if(lt[nod]>=i&&rt[nod]<=j)return t[nod];
	int mid=lt[nod]+rt[nod]>>1,ans=0;
	if(i<=mid)ans+=ssum(i,j,nod*2);
	if(j>mid)ans+=ssum(i,j,nod*2+1);
	return ans;
}
signed main()
{
	n=read();q=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);
	}
	dfs(1,1);
	for(int j=1;j<18;j++)
		for(int i=1;i<=n;i++)f[i][j]=f[f[i][j-1]][j-1];
	build(1,n,1);int Rt=1;
	while(q--){
		int op=read();
		if(op==1)Rt=read();
		if(op==2){
			int x=read(),y=read(),v=read();int LCA;
			if(sx[x]>sx[Rt]&&sx[x]<sx[Rt]+s[Rt]&&sx[y]>sx[Rt]&&sx[y]<sx[Rt]+s[Rt])LCA=lca(x,y);
			else{
				int X=lca(Rt,x),Y=lca(Rt,y);
				LCA=(deep[X]>deep[Y])?X:Y;
			}
			if(sx[LCA]==sx[Rt])xg(1,n,v,1);
			else if(lca(LCA,Rt)!=LCA)xg(sx[LCA],sx[LCA]+s[LCA]-1,v,1);
			else{
				xg(1,n,v,1);int k=up(Rt,deep[LCA]+1);
				xg(sx[k],sx[k]+s[k]-1,-v,1);
			}
		}
		if(op==3){
			int x=read();
			if(sx[x]==sx[Rt])writeln(ssum(1,n,1));
			else if(lca(x,Rt)!=x)writeln(ssum(sx[x],sx[x]+s[x]-1,1));
			else{
				int ans=ssum(1,n,1);int k=up(Rt,deep[x]+1);
				ans-=ssum(sx[k],sx[k]+s[k]-1,1);
				writeln(ans);
			}
		}
	}
	return 0;
}


#include <bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
	int k=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){k=k*10+ch-'0';ch=getchar();}
	return k*f;
}
inline void write(int x){
	if(x<0)putchar('-'),x=-x;
	if(x>9)write(x/10);putchar(x%10+'0');
}
inline void writeln(int x){
	write(x);puts("");
}
int nedge=0,p[200010],nex[200010],head[200010];
int n,q,a[100010],f[100010][18],deep[100010],sx[100010],xs[100010],cnt=0,s[100010];
inline void addedge(int a,int b){
	p[++nedge]=b;nex[nedge]=head[a];head[a]=nedge;
}
inline void dfs(int x,int dep){
	deep[x]=dep;sx[x]=++cnt;xs[cnt]=x;s[x]=1;
	for(int k=head[x];k;k=nex[k])if(p[k]!=f[x][0]){
		f[p[k]][0]=x;dfs(p[k],dep+1);
		s[x]+=s[p[k]];
	}
}
inline int up(int x,int dep){
	for(int i=17;i>=0;i--)if(deep[f[x][i]]>=dep)x=f[x][i];
	return x;
}
inline int lca(int x,int y){
	if(deep[x]<deep[y])swap(x,y);
	x=up(x,deep[y]);
	for(int i=17;i>=0;i--)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
	if(x!=y)x=f[x][0];return x;
}
int t[400010],lt[400010],rt[400010],add[400010];
inline void build(int l,int r,int nod){
	lt[nod]=l;rt[nod]=r;add[nod]=0;
	if(l==r){t[nod]=a[xs[l]];return;}
	int mid=l+r>>1;
	build(l,mid,nod*2);build(mid+1,r,nod*2+1);
	t[nod]=t[nod*2]+t[nod*2+1];
}
inline void pushdown(int nod){
	if(!add[nod])return;
	if(lt[nod]!=rt[nod]){
		t[nod*2]+=(rt[nod*2]-lt[nod*2]+1)*add[nod];
		t[nod*2+1]+=(rt[nod*2+1]-lt[nod*2+1]+1)*add[nod];
		add[nod*2]+=add[nod];add[nod*2+1]+=add[nod];
	}add[nod]=0;
}
inline void xg(int i,int j,int v,int nod){
	pushdown(nod);
	if(lt[nod]>=i&&rt[nod]<=j){
		t[nod]+=(rt[nod]-lt[nod]+1)*v;add[nod]+=v;
		return;
	}
	int mid=lt[nod]+rt[nod]>>1;
	if(i<=mid)xg(i,j,v,nod*2);
	if(j>mid)xg(i,j,v,nod*2+1);
	t[nod]=t[nod*2]+t[nod*2+1];
}
inline int ssum(int i,int j,int nod){
	pushdown(nod);
	if(lt[nod]>=i&&rt[nod]<=j)return t[nod];
	int mid=lt[nod]+rt[nod]>>1,ans=0;
	if(i<=mid)ans+=ssum(i,j,nod*2);
	if(j>mid)ans+=ssum(i,j,nod*2+1);
	return ans;
}
signed main()
{
	n=read();q=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);
	}
	dfs(1,1);
	for(int j=1;j<18;j++)
		for(int i=1;i<=n;i++)f[i][j]=f[f[i][j-1]][j-1];
	build(1,n,1);int Rt=1;
	while(q--){
		int op=read();
		if(op==1)Rt=read();
		if(op==2){
			int x=read(),y=read(),v=read();int LCA;
			if(sx[x]>sx[Rt]&&sx[x]<sx[Rt]+s[Rt]&&sx[y]>sx[Rt]&&sx[y]<sx[Rt]+s[Rt])LCA=lca(x,y);
			else{
				int X=lca(Rt,x),Y=lca(Rt,y);
				LCA=(deep[X]>deep[Y])?X:Y;
			}
			if(sx[LCA]==sx[Rt])xg(1,n,v,1);
			else if(sx[LCA]>sx[Rt]&&sx[LCA]<sx[Rt]+s[Rt])xg(sx[LCA],sx[LCA]+s[LCA]-1,v,1);
			else{
				xg(1,n,v,1);int k=up(Rt,deep[LCA]+1);
				xg(sx[k],sx[k]+s[k]-1,-v,1);
			}
		}
		if(op==3){
			int x=read();
			if(sx[x]==sx[Rt])writeln(ssum(1,n,1));
			else if(sx[x]>sx[Rt]&&sx[x]<sx[Rt]+s[Rt])writeln(ssum(sx[x],sx[x]+s[x]-1,1));
			else{
				int ans=ssum(1,n,1);int k=up(Rt,deep[x]+1);
				ans-=ssum(sx[k],sx[k]+s[k]-1,1);
				writeln(ans);
			}
		}
	}
	return 0;
}


#include <bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
	int k=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){k=k*10+ch-'0';ch=getchar();}
	return k*f;
}
inline void write(int x){
	if(x<0)putchar('-'),x=-x;
	if(x>9)write(x/10);putchar(x%10+'0');
}
inline void writeln(int x){
	write(x);puts("");
}
int nedge=0,p[200010],nex[200010],head[200010];
int n,q,a[100010],f[100010][18],deep[100010],sx[100010],xs[100010],cnt=0,s[100010];
inline void addedge(int a,int b){
	p[++nedge]=b;nex[nedge]=head[a];head[a]=nedge;
}
inline void dfs(int x,int dep){
	deep[x]=dep;sx[x]=++cnt;xs[cnt]=x;s[x]=1;
	for(int k=head[x];k;k=nex[k])if(p[k]!=f[x][0]){
		f[p[k]][0]=x;dfs(p[k],dep+1);
		s[x]+=s[p[k]];
	}
}
inline int up(int x,int dep){
	for(int i=17;i>=0;i--)if(deep[f[x][i]]>=dep)x=f[x][i];
	return x;
}
inline int lca(int x,int y){
	if(deep[x]<deep[y])swap(x,y);
	x=up(x,deep[y]);
	for(int i=17;i>=0;i--)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
	if(x!=y)x=f[x][0];return x;
}
int t[400010],lt[400010],rt[400010],add[400010];
inline void build(int l,int r,int nod){
	lt[nod]=l;rt[nod]=r;add[nod]=0;
	if(l==r){t[nod]=a[xs[l]];return;}
	int mid=l+r>>1;
	build(l,mid,nod*2);build(mid+1,r,nod*2+1);
	t[nod]=t[nod*2]+t[nod*2+1];
}
inline void pushdown(int nod){
	if(!add[nod])return;
	if(lt[nod]!=rt[nod]){
		t[nod*2]+=(rt[nod*2]-lt[nod*2]+1)*add[nod];
		t[nod*2+1]+=(rt[nod*2+1]-lt[nod*2+1]+1)*add[nod];
		add[nod*2]+=add[nod];add[nod*2+1]+=add[nod];
	}add[nod]=0;
}
inline void xg(int i,int j,int v,int nod){
	pushdown(nod);
	if(lt[nod]>=i&&rt[nod]<=j){
		t[nod]+=(rt[nod]-lt[nod]+1)*v;add[nod]+=v;
		return;
	}
	int mid=lt[nod]+rt[nod]>>1;
	if(i<=mid)xg(i,j,v,nod*2);
	if(j>mid)xg(i,j,v,nod*2+1);
	t[nod]=t[nod*2]+t[nod*2+1];
}
inline int ssum(int i,int j,int nod){
	pushdown(nod);
	if(lt[nod]>=i&&rt[nod]<=j)return t[nod];
	int mid=lt[nod]+rt[nod]>>1,ans=0;
	if(i<=mid)ans+=ssum(i,j,nod*2);
	if(j>mid)ans+=ssum(i,j,nod*2+1);
	return ans;
}
signed main()
{
	n=read();q=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);
	}
	dfs(1,1);
	for(int j=1;j<18;j++)
		for(int i=1;i<=n;i++)f[i][j]=f[f[i][j-1]][j-1];
	build(1,n,1);int Rt=1;
	while(q--){
		int op=read();
		if(op==1)Rt=read();
		if(op==2){
			int x=read(),y=read(),v=read();int LCA=lca(x,y);
			if(sx[LCA]==sx[Rt])xg(1,n,v,1);
			else if(sx[LCA]>sx[Rt]&&sx[LCA]<sx[Rt]+s[Rt])xg(sx[LCA],sx[LCA]+s[LCA]-1,v,1);
			else{
				xg(1,n,v,1);int k=up(Rt,deep[LCA]+1);
				xg(sx[k],sx[k]+s[k]-1,-v,1);
			}
		}
		if(op==3){
			int x=read();
			if(sx[x]==sx[Rt])writeln(ssum(1,n,1));
			else if(sx[x]>sx[Rt]&&sx[x]<sx[Rt]+s[Rt])writeln(ssum(sx[x],sx[x]+s[x]-1,1));
			else{
				int ans=ssum(1,n,1);int k=up(Rt,deep[x]+1);
				ans-=ssum(sx[k],sx[k]+s[k]-1,1);
				writeln(ans);
			}
		}
	}
	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()
{
//	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), t3=LCA(root,v);
				if (dep[t3] > dep[t1]) t1 = t3;
				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()
{
//	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(root, u), t2 = LCA(u, v), t3=LCA(root,v);
			if (dep[t3] > dep[t1]) t1 = t3;
			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 endl '\n'
using namespace std;
typedef long long ll;
typedef unsigned long long llu;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<vi> vvi;
typedef pair<int, int> pii;
typedef vector<pii> vii;

// Add defines here ...
const int MAXN = 100000 + 5, MAXNLOG = 22;
const int MOD = 1e9 + 7;
const int INF = 1e9;
const int BASE = 31;

// Input
#define LCHILD(x) ((x)<<1)
#define RCHILD(x) (((x)<<1)+1)
#define RPARENT(x) ((x)>>1)

int N, M, Q;
vi G[MAXN];
int sparse[MAXN][MAXNLOG], level[MAXN];
int A[MAXN], order_start[MAXN], order_end[MAXN], curr_root, order_pos;

// LCA + Binary Lifting
void dfs(int p, int r) {

	sparse[r][0] = p;
	level[r] = level[p] + 1;
	order_start[r] = order_pos ++;
	for (int i = 0; i < G[r].size(); ++i) {
		int u = G[r][i];
		if(u != p)
			dfs(r, u);
	}
	order_end[r] = order_pos - 1;
}
// Build sparse table. sparse[i][j] = for node i get the (2^j)-th parent
void build_sparse() {
	for (int j = 1; j < MAXNLOG; ++j) {
		for (int i = 1; i < MAXN; ++i) {
			sparse[i][j] = sparse[sparse[i][j-1]][j-1];
		}
	}
}
// Kth parent of node u (binary lifting). If not exist return 0.
int kth_ancs(int u, int k) {
	for (int i = MAXNLOG - 1; i >= 0; --i) {
		if (k & (1<<i))
			u = sparse[u][i];
	}
	return u;
}
// LCA using binary lifting. First put nodes on the same level,
// next lift the nodes to the children-level of the lca.
int LCA(int u, int v) {

	if (level[u] < level[v]) swap(u, v);
	int ldif = level[u] - level[v];
	u = kth_ancs(u, ldif);

	//cout << "nodes: " << u << " " << v << endl;

	if (u == v) return u;

	for (int i = MAXNLOG - 1; i >= 0; --i)
		if (sparse[u][i] != sparse[v][i]) {
			u = sparse[u][i];
			v = sparse[v][i];
			//cout << "nodes(kth=" << i << "): " << u << " " << v << endl;
	}
	// u and v are at children-level of the lca, so lca is the parent.
	return sparse[u][0];
}

// Lazy segment tree
class STREE {

private:
	//static const int MOD = 1000000009;
	int size;
	vector<ll> stree;
	vector<ll> lazy;

	void __build(int root, int l, int r) {

		if(r > l) {
			__build(2*root, l, (l+r)/2);
			__build(2*root +1, (l+r)/2 +1, r);
		}

		if(l == r) {
			stree[root] = A[l];
			lazy[root] = 0;
		}
		else {
			stree[root] = stree[2*root] + stree[2*root + 1];
			lazy[root] = 0;
		}
	}

	// A node is always updated. Lazy is pushed to children when needed to go down
	void __pushLazy(int root, ll lazyValue, int l, int r) {

		int mid = (l+r)/2;

		stree[root*2] += lazyValue*(mid-l+1);
		//stree[root*2] %= MOD;
		lazy[root*2] += lazyValue;
		//lazy[root*2] %= MOD;

		stree[root*2 +1] += lazyValue*(r-mid);
		// stree[root*2 +1] %= MOD;
		lazy[root*2 +1] += lazyValue;
		// lazy[root*2 +1] %= MOD;

		lazy[root] = 0;
	}

	void __updateRange(int root, int i, int j, const int l, const int r, const ll val) {

		// Completely out-range
		if(i > j || i > r || j < l) return;

		// Completely in-range
		if(i >= l && j <= r) {
			// Update node and lazy value(to push() later)
			stree[root] += val*(j-i+1);
			//stree[root] %= MOD;
			lazy[root] += val;
			//lazy[root] %= MOD;

			return;
		}

		// If you go down into node children, you need to:
		// 1: Push lazy stored values
		// 2: Split the range
		// 3: Update node value with children values

		// Push lazy value to children
		__pushLazy(root, lazy[root], i, j);

		// Partialy in-range
		__updateRange(2*root, i, (i+j)/2, l, r, val);
		__updateRange(2*root +1, (i+j)/2 +1, j, l, r, val);

		// Update parent value
		stree[root] = stree[root*2] + stree[root*2 +1];
	}

	llu __queryRange(int root, int i, int j, const int l, const int r) {

		// Completely out-range
		if(i > j || i > r || j < l) return 0;

		// Completely in-range
		if(i >= l && j <= r) {
			return stree[root];
		}

		// Push lazy value to children
		__pushLazy(root, lazy[root], i, j);
		// Partialy in-range
		llu v1 = __queryRange(2*root, i, (i+j)/2, l, r);
		llu v2 = __queryRange(2*root +1, (i+j)/2 +1, j, l, r);

		return v1 + v2;
	}

public:
	STREE() {
		this->size = 0;
	}

	void createStree(int size) {
		this->size = size;

		stree.assign(size*4, 0);
		lazy.assign(size*4, 0);

		__build(1, 0, size - 1);
	}
	void updateRange(int x, int y, int val) {
		__updateRange(1, 0, this->size -1, x, y, val);
	}
	llu queryRange(int x, int y) {
		return __queryRange(1, 0, this->size -1, x, y);
	}

};

int main() {

	//Input region
	#ifdef GHOST
	system("subl name.in");
	freopen("name.in", "r", stdin);
	FILE * FILE_NAME = freopen("name.out", "w", stdout);
	int TIME = clock();
	#endif

	std::ios::sync_with_stdio(false); cin.tie(0);
	//Add your code here...

	cin >> N >> Q;

	for (int i = 0; i < N; ++i) {
		cin >> A[i];
	}
	int u, v;
	for (int i = 1; i < N; ++i) {
		cin >> u >> v;
		G[u].push_back(v);
		G[v].push_back(u);
	}

	// init
	curr_root = 1;
	dfs(0, 1);
	build_sparse();
	STREE S;
	S.createStree(N);

	// for (int i = 1; i <= order_pos; ++i)
	// {
	// 	cout << order_start[i] << " " << order_end[i] << endl;
	// }

	int op, x;
	while(Q--) {

		cin >> op;
		if(op == 1) {
			cin >> v;
			curr_root = v;
		}
		else if(op == 2) {
			cin >> u >> v >> x;

			int lca = LCA(u, v);
			//cout << "LCA of (" << u << ", " << v << ") == " << lca << endl;
			// Both u and v are in cur_root subtree
			if(	order_start[u] >= order_start[curr_root] && order_start[u] <= order_end[curr_root] &&
				order_start[v] >= order_start[curr_root] && order_start[v] <= order_end[curr_root]) {

				S.updateRange(order_start[lca], order_end[lca], x);
			}
			else {

				S.updateRange(0, N - 1, x);

				int lca1 = LCA(curr_root, u);
				int lca2 = LCA(curr_root, v);
				int modlca = (level[lca1] > level[lca2]) ? lca1 : lca2;
				//cout << "MOD_LCA of (" << u << ", " << v << ") == " << modlca << endl;
				int ldif = level[curr_root] - level[modlca] - 1;
				int ancs = kth_ancs(curr_root, ldif);
				if(ancs)
					S.updateRange(order_start[ancs], order_end[ancs], -x);
			}
		}
		else {
			cin >> v;
			//cout << "Query: " << order_start[v] << " -> " << order_end[v] << endl;
			int sum = S.queryRange(order_start[v], order_end[v]);
			// if curr_root is in v subtree, substract that subtree from total sum
			if(order_start[curr_root] > order_start[v] && order_start[curr_root] <= order_end[v]) {
				int ldif = level[curr_root] - level[v] - 1;
				int ancs = kth_ancs(curr_root, ldif);
				//cout << ldif << "-th ancs of " << curr_root << " == " << ancs << endl;

				sum = S.queryRange(0, N - 1);
				if(ancs)
					sum -= S.queryRange(order_start[ancs], order_end[ancs]);
			}
			cout << sum << endl;
		}

		//cout << "All sum == " << S.queryRange(0, N - 1) << endl;

	}

	//Output region
	#ifdef GHOST
	cout << "\n\nTIME: " << (clock() - TIME) << " MS" << endl;
	cout.flush();
	fclose(FILE_NAME);
	system("subl name.out");
	#endif

	return 0;
}


#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
typedef long long ll;
typedef unsigned long long llu;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<vi> vvi;
typedef pair<int, int> pii;
typedef vector<pii> vii;

// Add defines here ...
const int MAXN = 100000 + 5, MAXNLOG = 22;
const int MOD = 1e9 + 7;
const int INF = 1e9;
const int BASE = 31;

// Input
#define LCHILD(x) ((x)<<1)
#define RCHILD(x) (((x)<<1)+1)
#define RPARENT(x) ((x)>>1)

int N, M, Q;
vi G[MAXN];
int sparse[MAXN][MAXNLOG], level[MAXN];
int A[MAXN], order_start[MAXN], order_end[MAXN], curr_root, order_pos;
int pos_nodes[MAXN];

// LCA + Binary Lifting
void dfs(int p, int r) {

	sparse[r][0] = p;
	level[r] = level[p] + 1;
	order_start[r] = order_pos;
	pos_nodes[order_pos] = r;
	order_pos ++;
	for (int i = 0; i < G[r].size(); ++i) {
		int u = G[r][i];
		if(u != p)
			dfs(r, u);
	}
	order_end[r] = order_pos - 1;
}
// Build sparse table. sparse[i][j] = for node i get the (2^j)-th parent
void build_sparse() {
	for (int j = 1; j < MAXNLOG; ++j) {
		for (int i = 1; i < MAXN; ++i) {
			sparse[i][j] = sparse[sparse[i][j-1]][j-1];
		}
	}
}
// Kth parent of node u (binary lifting). If not exist return 0.
int kth_ancs(int u, int k) {
	if(k < 0) return 0;
	for (int i = MAXNLOG - 1; i >= 0; --i) {
		if (k & (1<<i))
			u = sparse[u][i];
	}
	return u;
}
// Using dfs order to determine if u == v or u is ancestor of v
bool is_ancs(int u, int v) {
	return (order_start[v] >= order_start[u] && order_start[v] <= order_end[u]);
}
// LCA using binary lifting. First put nodes on the same level,
// next lift the nodes to the children-level of the lca.
int LCA(int u, int v) {

	if (level[u] < level[v]) swap(u, v);
	int ldif = level[u] - level[v];
	u = kth_ancs(u, ldif);

	//cout << "nodes: " << u << " " << v << endl;

	if (u == v) return u;

	for (int i = MAXNLOG - 1; i >= 0; --i)
		if (sparse[u][i] != sparse[v][i]) {
			u = sparse[u][i];
			v = sparse[v][i];
			//cout << "nodes(kth=" << i << "): " << u << " " << v << endl;
	}
	// u and v are at children-level of the lca, so lca is the parent.
	return sparse[u][0];
}

// Lazy segment tree
class STREE {

private:
	//static const int MOD = 1000000009;
	int size;
	vector<ll> stree;
	vector<ll> lazy;

	void __build(int root, int l, int r) {

		if(r > l) {
			__build(2*root, l, (l+r)/2);
			__build(2*root +1, (l+r)/2 +1, r);
		}

		if(l == r) {
			stree[root] = A[ pos_nodes[l] - 1 ];
			lazy[root] = 0;
		}
		else {
			stree[root] = stree[2*root] + stree[2*root + 1];
			lazy[root] = 0;
		}
	}

	// A node is always updated. Lazy is pushed to children when needed to go down
	void __pushLazy(int root, ll lazyValue, int l, int r) {

		int mid = (l+r)/2;

		stree[root*2] += lazyValue*(mid-l+1);
		//stree[root*2] %= MOD;
		lazy[root*2] += lazyValue;
		//lazy[root*2] %= MOD;

		stree[root*2 +1] += lazyValue*(r-mid);
		// stree[root*2 +1] %= MOD;
		lazy[root*2 +1] += lazyValue;
		// lazy[root*2 +1] %= MOD;

		lazy[root] = 0;
	}

	void __updateRange(int root, int i, int j, const int l, const int r, const ll val) {

		// Completely out-range
		if(i > j || i > r || j < l) return;

		// Completely in-range
		if(i >= l && j <= r) {
			// Update node and lazy value(to push() later)
			stree[root] += val*(j-i+1);
			//stree[root] %= MOD;
			lazy[root] += val;
			//lazy[root] %= MOD;

			return;
		}

		// If you go down into node children, you need to:
		// 1: Push lazy stored values
		// 2: Split the range
		// 3: Update node value with children values

		// Push lazy value to children
		__pushLazy(root, lazy[root], i, j);

		// Partialy in-range
		__updateRange(2*root, i, (i+j)/2, l, r, val);
		__updateRange(2*root +1, (i+j)/2 +1, j, l, r, val);

		// Update parent value
		stree[root] = stree[root*2] + stree[root*2 +1];
	}

	llu __queryRange(int root, int i, int j, const int l, const int r) {

		// Completely out-range
		if(i > j || i > r || j < l) return 0;

		// Completely in-range
		if(i >= l && j <= r) {
			return stree[root];
		}

		// Push lazy value to children
		__pushLazy(root, lazy[root], i, j);
		// Partialy in-range
		llu v1 = __queryRange(2*root, i, (i+j)/2, l, r);
		llu v2 = __queryRange(2*root +1, (i+j)/2 +1, j, l, r);

		return v1 + v2;
	}

public:
	STREE() {
		this->size = 0;
	}

	void createStree(int size) {
		this->size = size;

		stree.assign(size*4, 0);
		lazy.assign(size*4, 0);

		__build(1, 0, size - 1);
	}
	void updateRange(int x, int y, int val) {
		__updateRange(1, 0, this->size -1, x, y, val);
	}
	llu queryRange(int x, int y) {
		return __queryRange(1, 0, this->size -1, x, y);
	}

};

int main() {

	//Input region
	#ifdef GHOST
	system("subl name.in");
	freopen("name.in", "r", stdin);
	FILE * FILE_NAME = freopen("name.out", "w", stdout);
	int TIME = clock();
	#endif

	std::ios::sync_with_stdio(false); cin.tie(0);
	//Add your code here...

	cin >> N >> Q;

	for (int i = 0; i < N; ++i) {
		cin >> A[i];
	}
	int u, v;
	for (int i = 1; i < N; ++i) {
		cin >> u >> v;
		G[u].push_back(v);
		G[v].push_back(u);
	}

	// init
	curr_root = 1;
	dfs(0, 1);
	build_sparse();
	STREE S;
	S.createStree(N);

	// for (int i = 1; i <= order_pos; ++i)
	// {
	// 	cout << order_start[i] << " " << order_end[i] << endl;
	// }

	int op, x;
	while(Q--) {

		cin >> op;
		if(op == 1) {
			cin >> v;
			curr_root = v;
		}
		else if(op == 2) {

			cin >> u >> v >> x;

			int lca = LCA(u, v);
			//cout << "LCA of (" << u << ", " << v << ") == " << lca << endl;
			if(is_ancs(lca, curr_root)) {

				int lca1 = LCA(curr_root, u);
				int lca2 = LCA(curr_root, v);
				int modlca = (level[lca1] > level[lca2]) ? lca1 : lca2;

				S.updateRange(0, N - 1, x);
				int ldif = level[curr_root] - level[modlca] - 1;
				int ancs = kth_ancs(curr_root, ldif);
				if(ancs)
					S.updateRange(order_start[ancs], order_end[ancs], -x);
			}
			else {

				S.updateRange(order_start[lca], order_end[lca], x);
			}
		}
		else {

			cin >> v;
			ll sum = 0;

			if(is_ancs(v, curr_root)) {

				//cout << v << " is ancs if root " << curr_root << endl;

				sum = S.queryRange(0, N - 1);

				int ldif = level[curr_root] - level[v] - 1;
				int ancs = kth_ancs(curr_root, ldif);
				//cout << ldif << "-th ancs of " << curr_root << " == " << ancs << endl;
				if(ancs)
					sum -= S.queryRange(order_start[ancs], order_end[ancs]);
			}
			else {
				//cout << v << " is in origin" << endl;
				//cout << order_start[v] << " " << order_end[v] << endl;
				sum = S.queryRange(order_start[v], order_end[v]);
			}
			cout << sum << endl;
		}
		//cout << "All sum == " << S.queryRange(0, N - 1) << endl;

	}

	//Output region
	#ifdef GHOST
	cout << "\n\nTIME: " << (clock() - TIME) << " MS" << endl;
	cout.flush();
	fclose(FILE_NAME);
	system("subl name.out");
	#endif

	return 0;
}


#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(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<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(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;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<<endl;
				//cout<<tree[1].sum<<" ";

				//cout<<endl;
				int now=getp(x);
				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));
			}
		}
	}
}