#pragma GCC optimize ("O3")
#include <bits/stdc++.h>
#include <bits/extc++.h>
using namespace std;
using namespace __gnu_pbds;
using namespace __gnu_cxx;
const int maxn = 1e5+ 5;
vector<int> G[maxn];
int sz[maxn],fa[maxn],dep[maxn],zson[maxn],top[maxn],dfn[maxn],vis=1,a[maxn];
void dfs(int d)
{
dep[d]=dep[fa[d]]+1;
sz[d]=1;
for (auto i:G[d])
{
if (i!=fa[d])
{
fa[i]=d;
dfs(i);
sz[d]+=sz[i];
if (sz[i]>sz[zson[d]])
zson[d]=i;
}
}
}
void gettop(int d,int tp)
{
top[d]=tp;
dfn[d]=vis;
a[vis]=d;
vis++;
if (zson[d])
gettop(zson[d],tp);
for (auto i:G[d])
if (i!=fa[d]&&i!=zson[d])
gettop(i,i);
}
void add2(int l,int r,int w)
{
for (int i=l;i<=r;i++)
a[i]+=w;
}
void add1(int x,int y,int z)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
swap(x,y);
add2(dfn[top[x]],dfn[x],z);
x=fa[top[x]];
}
add2(min(dfn[x],dfn[y]),max(dfn[x],dfn[y]),z);
}
int sum(int l,int r)
{
int ans=0;
for (int i=l;i<=r;i++)
ans^=a[i];
return ans;
}
int query1(int x,int y)
{
int ans=0;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
swap(x,y);
ans^=sum(dfn[top[x]],dfn[x]);
x=fa[top[x]];
}
ans^=sum(min(dfn[x],dfn[y]),max(dfn[x],dfn[y]));
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int n,q,u,v,w;
char op;
cin>>n>>q;
for (int i=1;i<n;i++)
{
cin>>u>>v;
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1);
gettop(1,1);
while (q--)
{
cin>>op>>u>>v;
if (op=='+')
{
cin>>w;
add1(u,v,w);
}
else
cout<<query1(u,v)<<'\n';
}
}