#include #define rep(i,n) for(int i=0;i<(n);i++) using namespace std; using graph=vector>; void add_edge(graph& G,int u,int v){ G[u].emplace_back(v); G[v].emplace_back(u); } class union_find{ int n; vector p; public: union_find(int n):n(n),p(n,-1){} int find(int u){ return p[u]<0?u:p[u]=find(p[u]); } void unite(int u,int v){ u=find(u); v=find(v); if(u!=v){ // 常に u を親にする // if(p[v] L,R; const graph& Tr; int idx; void dfs(int u,int p){ L[u]=idx++; for(int v:Tr[u]) if(v!=p) dfs(v,u); R[u]=idx; } public: Euler_tour_for_vertex(const graph& Tr,int root):L(Tr.size()),R(Tr.size()),Tr(Tr),idx(0){ dfs(root,-1); } int get_index(int u)const{ return L[u]; } pair get_subtree(int u)const{ return {L[u],R[u]}; } }; template class segment_tree{ int n; vector dat; void add(int l,int r,int a,int b,int u,T v){ if(l<=a && b<=r){ dat[u]+=v; return; } int c=(a+b+1)/2; if(l=1;u/=2) res+=dat[u]; return res; } }; int main(){ int n,q; scanf("%d%d",&n,&q); int m=n; union_find U(n); graph T(n); vector> Q; rep(i,q){ int type,a,b; scanf("%d%d%d",&type,&a,&b); if(type==1){ a--; b--; a=U.find(a); b=U.find(b); if(a!=b){ U.make_set(); U.unite(m,a); U.unite(m,b); T.emplace_back(); add_edge(T,m,a); add_edge(T,m,b); m++; } } else if(type==2){ a--; a=U.find(a); Q.emplace_back(type,a,b); } else{ a--; Q.emplace_back(type,a,b); } } // T を連結にする { queue Q; rep(u,n) if(U.size(u) ST(m); rep(i,Q.size()){ int type,a,b; tie(type,a,b)=Q[i]; if(type==2){ int l,r; tie(l,r)=ET.get_subtree(a); ST.add(l,r,b); } else{ printf("%d\n",ST.query(ET.get_index(a))); } } return 0; }