#include #include #include #include using namespace std; typedef int OBJ_ID; typedef int STK_ID; class UnionFind { map lnk; map lnkSiz; map stk; map stkSiz; public: void link( OBJ_ID x, OBJ_ID y ) { link_repr( repr(x), repr(y) ); } int size( STK_ID s ) { return stkSiz[s]; } void alloc( OBJ_ID x, STK_ID s ) { stk[x] = s; lnkSiz[x] = 1; stkSiz[s]++; } private: OBJ_ID repr( OBJ_ID x ) { // ここでPath圧縮すると計算量が nlog(n) から n ack^-1(n) に while( lnk.count(x) ) x = lnk[x]; return x; } void link_repr( OBJ_ID x, OBJ_ID y ) { if( x == y ) return; // 所属スタックの情報とかをマージ int sx=stk[x], sy=stk[y]; if( sx < sy ) { stkSiz[sy] -= lnkSiz[y]; stkSiz[sx] += lnkSiz[y]; stk[y] = sx; } else if( sx > sy ) { stkSiz[sx] -= lnkSiz[x]; stkSiz[sy] += lnkSiz[x]; stk[x] = sy; } // グループ化 if( lnkSiz[x] < lnkSiz[y] ) { lnk[x] = y; lnkSiz[y] += lnkSiz[x]; } else { lnk[y] = x; lnkSiz[x] += lnkSiz[y]; } } }; int main() { for(int L,M,N; cin>>L,L; ) { // スタックやリンクの状態を管理する変数 STK_ID nextStackID = 1; OBJ_ID nextObjID = 1; vector stack(1, 0); UnionFind uf; // L個の命令を処理 for(int i=0; i!=L; ++i) { string cmd; cin>>cmd; if( cmd == "alloc" ) uf.alloc( nextObjID++, stack.back() ); else if( cmd == "call" ) stack.push_back( nextStackID++ ); else if( cmd == "link" ) cin >> N >> M, uf.link( N, M ); else if( cmd == "return" ) cout << uf.size(stack.back()) << endl, stack.pop_back(); } } }