#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
inline int read(){
int num=0,sign=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')
sign=-sign;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
num=num*10+(int)ch-48;
ch=getchar();
}
return num*sign;
}
int T,n,q,timer;
int fa[1000009],colors[1000009];
ll d[1000009];
int level[1000009];
int in[1000009];
int st_min[20][1000009];
vector<pair<int,int> > reach[1000009];
struct querying{
int op;
int c;
ll d;
int activate;
}query[1000009];
inline void dfs(int u){
in[u]=++timer;
st_min[0][in[u]]=u;
for(int i=0;i<reach[u].size();i++){
pair<int,int> tmp=reach[u][i];
level[tmp.first]=level[u]+1;
d[tmp.first]=d[u]+tmp.second;
dfs(tmp.first);
}
}
inline void cout_dfs_stuff(){
printf("%d\nrec:\n",timer);
printf("\nin:\n");
for(int i=1;i<=timer;i++)
printf("%d ",in[i]);
printf("\nout:\n");
printf("\nlevel:\n");
for(int i=1;i<=timer;i++)
printf("%d ",level[i]);
printf("\nd:\n");
for(int i=1;i<=timer;i++)
printf("%d ",d[i]);
printf("\n");
}
inline int check_min(int u,int v){
return level[u]<level[v]?u:v;
}
inline void init_sparse_table(){
for(int i=1;i<=19;i++)
for(int j=1;j<=n-(1<<i)+1;j++)
st_min[i][j]=check_min(st_min[i-1][j],st_min[i-1][j+(1<<i-1)]);
}
inline void cout_sparse_table(){
printf("st:\n");
for(int i=0;i<=ceil(log2(500000));i++){
printf("%d\n\n",i);
for(int j=1;j<=n-(1<<i)-1;j++)
printf("%d %d\n",j,st_min[i][j]);
}
}
inline int find_lca(int u,int v){
if(u==v)
return u;
u=in[u]; v=in[v];
if(u>v)
swap(u,v);
int len=__lg(v-u);
return fa[check_min(st_min[len][u+1],st_min[len][v-(1<<len)+1])];
}
inline ll find_distance(int u,int v){
int cnt=(u==0)+(v==0);
if(cnt>0)
return -cnt;
return d[u]+d[v]-2*d[find_lca(u,v)];
}
struct diameter{
pair<int,int> furthest;
};
inline int check_diameter(diameter u,diameter v){
return find_distance(u.furthest.first,u.furthest.second)>find_distance(v.furthest.first,v.furthest.second);
}
inline diameter check_max(diameter ans,int u,int v){
int dist=find_distance(u,v);
if(find_distance(ans.furthest.first,ans.furthest.second)<dist){
ans.furthest=make_pair(u,v);
}
return ans;
}
inline diameter merge(diameter u,diameter v){
diameter ans=u;
ans=check_max(ans,v.furthest.first,v.furthest.second);
ans=check_max(ans,u.furthest.first,v.furthest.first);
ans=check_max(ans,u.furthest.first,v.furthest.second);
ans=check_max(ans,u.furthest.second,v.furthest.first);
ans=check_max(ans,u.furthest.second,v.furthest.second);
return ans;
}
int nP;
int rt[1000009];
struct dynamic_open_point_sgt1{
int son[2];
diameter longest;
}tr[20000009];
inline void pushup_dynamic_open_point_sgt1(int u){
if(tr[u].son[0]==0&&tr[u].son[1]==0){
tr[u].longest.furthest=make_pair(0,0);
return;
}
if(tr[u].son[0]==0){
tr[u].longest=tr[tr[u].son[1]].longest;
return;
}
if(tr[u].son[1]==0){
tr[u].longest=tr[tr[u].son[0]].longest;
return;
}
tr[u].longest=merge(tr[tr[u].son[0]].longest,tr[tr[u].son[1]].longest);
}
inline int ins_dynamic_open_point_sgt1(int u,int l,int r,int id){
if(u==0)
u=++nP;
if(l==r){
tr[u].longest.furthest=make_pair(id,id);
return u;
}
int mid=(l+r)>>1;
if(id<=mid)
tr[u].son[0]=ins_dynamic_open_point_sgt1(tr[u].son[0],l,mid,id);
else
tr[u].son[1]=ins_dynamic_open_point_sgt1(tr[u].son[1],mid+1,r,id);
pushup_dynamic_open_point_sgt1(u);
return u;
}
inline int del_dynamic_open_point_sgt1(int u,int l,int r,int id){
if(u==0)
u=++nP;
if(l==r){
tr[u].longest.furthest=make_pair(0,0);
return u;
}
int mid=(l+r)>>1;
if(id<=mid)
tr[u].son[0]=del_dynamic_open_point_sgt1(tr[u].son[0],l,mid,id);
else
tr[u].son[1]=del_dynamic_open_point_sgt1(tr[u].son[1],mid+1,r,id);
pushup_dynamic_open_point_sgt1(u);
return u;
}
inline void re_init_dynamic_open_point_sgt1(){
for(int i=1;i<=q+1;i++)
rt[i]=0;
for(int i=1;i<=nP;i++){
tr[i].son[0]=0; tr[i].son[1]=0;
tr[i].longest.furthest=make_pair(0,0);
}
nP=0;
}
struct segtree{
int l,r;
diameter longest[2];
}tr2[4000009];
inline diameter merge2(diameter u,diameter v,diameter x,diameter y){
diameter ans=x;
ans=check_max(ans,y.furthest.first,y.furthest.second);
ans=check_max(ans,u.furthest.first,v.furthest.first);
ans=check_max(ans,u.furthest.first,v.furthest.second);
ans=check_max(ans,u.furthest.second,v.furthest.first);
ans=check_max(ans,u.furthest.second,v.furthest.second);
ans=check_max(ans,u.furthest.first,y.furthest.first);
ans=check_max(ans,u.furthest.first,y.furthest.second);
ans=check_max(ans,u.furthest.second,y.furthest.first);
ans=check_max(ans,u.furthest.second,y.furthest.second);
ans=check_max(ans,x.furthest.first,v.furthest.first);
ans=check_max(ans,x.furthest.first,v.furthest.second);
ans=check_max(ans,x.furthest.second,v.furthest.first);
ans=check_max(ans,x.furthest.second,v.furthest.second);
ans=check_max(ans,x.furthest.first,y.furthest.first);
ans=check_max(ans,x.furthest.first,y.furthest.second);
ans=check_max(ans,x.furthest.second,y.furthest.first);
ans=check_max(ans,x.furthest.second,y.furthest.second);
return ans;
}
inline void pushup_sgt(int u){
tr2[u].longest[0]=merge(tr2[u*2].longest[0],tr2[u*2+1].longest[0]);
tr2[u].longest[1]=merge2(tr2[u*2].longest[0],tr2[u*2+1].longest[0],tr2[u*2].longest[1],tr2[u*2+1].longest[1]);
}
inline void build_sgt(int u,int l,int r){
tr2[u].l=l; tr2[u].r=r;
if(l==r)
return;
int mid=(l+r)>>1;
build_sgt(u*2,l,mid);
build_sgt(u*2+1,mid+1,r);
}
inline void upd_sgt(int u,int l,int r,int color,pair<int,int> rec){
if(l==r){
tr2[u].longest[0].furthest=rec;
tr2[u].longest[1].furthest=make_pair(0,0);
return;
}
int mid=(l+r)>>1;
if(color<=mid)
upd_sgt(u*2,l,mid,color,rec);
else
upd_sgt(u*2+1,mid+1,r,color,rec);
pushup_sgt(u);
}
inline void clear_sgt(int u,int l,int r){
tr2[u].longest[0].furthest=make_pair(0,0);
tr2[u].longest[1].furthest=make_pair(0,0);
if(l==r)
return;
int mid=(l+r)>>1;
clear_sgt(u*2,l,mid);
clear_sgt(u*2+1,mid+1,r);
}
inline void cout_sgt(int u){
printf("node: %d\n%d %d\n",u,tr2[u].l,tr2[u].r);
if(tr2[u].l==tr2[u].r)
return;
cout_sgt(u*2);
cout_sgt(u*2+1);
}
signed main(){
T=read();
while(T--){
n=1; timer=0; nP=0;
q=read(); colors[1]=read();
for(int i=1;i<=q;i++){
int op;
op=read();
query[i].op=op;
if(op==0){
int x,c;
ll d;
x=read(); c=read();
scanf("%lld",&d);
query[i].c=c; query[i].d=d;
n++; fa[n]=x;
reach[x].push_back(make_pair(n,d));
query[i].activate=n;
}
else{
int x,c;
x=read(); c=read();
query[i].c=c; query[i].activate=x;
}
}
for(int i=1;i<=n;i++){
level[i]=0; d[i]=0; in[i]=0;
if(i!=1)
colors[i]=0;
for(int j=0;j<=19;j++)
st_min[j][i]=0;
}
dfs(1);
init_sparse_table();
rt[colors[1]]=ins_dynamic_open_point_sgt1(rt[colors[1]],1,q+1,1);
upd_sgt(1,1,q+1,colors[1],tr[rt[colors[1]]].longest.furthest);
for(int i=1;i<=q;i++){
if(query[i].op==0){
colors[query[i].activate]=query[i].c;
rt[query[i].c]=ins_dynamic_open_point_sgt1(rt[colors[query[i].activate]],1,q+1,query[i].activate);
upd_sgt(1,1,q+1,colors[query[i].activate],tr[rt[colors[query[i].activate]]].longest.furthest);
}
else{
rt[colors[query[i].activate]]=del_dynamic_open_point_sgt1(rt[colors[query[i].activate]],1,q+1,query[i].activate);
upd_sgt(1,1,q+1,colors[query[i].activate],tr[rt[colors[query[i].activate]]].longest.furthest);
colors[query[i].activate]=query[i].c;
rt[query[i].c]=ins_dynamic_open_point_sgt1(rt[colors[query[i].activate]],1,q+1,query[i].activate);
upd_sgt(1,1,q+1,colors[query[i].activate],tr[rt[colors[query[i].activate]]].longest.furthest);
}
printf("%lld\n",max(0ll,find_distance(tr2[1].longest[1].furthest.first,tr2[1].longest[1].furthest.second)));
}
timer=0;
for(int i=1;i<=n;i++)
reach[i].clear();
re_init_dynamic_open_point_sgt1();
clear_sgt(1,1,q+1);
}
return 0;
}