If you draw a picture, you can only judge the iron wolf. If there is no certain villager, the iron wolf will exist in a ring. If there is only one person in the ring who is considered as a wolf, then he is the iron wolf. It is easy to see that this is an introverted tree in the ring. So you will find that if someone says that the iron wolf is a villager, the person who says that the wolf is a villager is Wolf. So we can think that some rings are useless rings. If there is a ring with villagers' edges, the ring is useless for eggs, so it will shrink directly. As for how to search for the answers, you can quickly think of how to determine the wolf on the ring first, and then expand outwards, so you can build a map in reverse direction. At this time, it is a map of an outward tree on the base ring, and if you only add the villagers' side, it will form a tree like appearance (although the directed map is not rigorous, but you can't imagine how to describe it), and the maximum penetration of each point is 1, so you can In order to facilitate violence. (burst the stack and change a dfs).
#include<bits/stdc++.h>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int maxn=100005;
struct edge{
int to,nxt;
}E[maxn],e[maxn],e1[maxn],e2[maxn];
int DFN[maxn],LOW[maxn],index;
int head1[maxn],head2[maxn],head3[maxn],head4[maxn];
int S[maxn],top;
bool ins[maxn];
int col[maxn],numc;
int ecnt1,ecnt2,ecnt3,ecnt4;
void ins1(int u,int v){
E[ecnt1].to=v;
E[ecnt1].nxt=head1[u];
head1[u]=ecnt1++;
}
void ins2(int u,int v){
e[ecnt2].to=v;
e[ecnt2].nxt=head2[u];
head2[u]=ecnt2++;
}
void ins3(int u,int v){
e1[ecnt3].to=v;
e1[ecnt3].nxt=head3[u];
head3[u]=ecnt3++;
}
void ins4(int u,int v){
e2[ecnt4].to=v;
e2[ecnt4].nxt=head4[u];
head4[u]=ecnt4++;
}
void Tarjan(int u){
DFN[u]=LOW[u]=++index;
S[++top]=u;
ins[u]=true;
for(int i=head1[u];i!=-1;i=E[i].nxt){
int v=E[i].to;
if(!DFN[v]){
Tarjan(v);
LOW[u]=min(LOW[u],LOW[v]);
}
else if(ins[v]) LOW[u]=min(LOW[u],DFN[v]);
}
if(DFN[u]==LOW[u]){
++numc;
while(S[top + 1]!=u){
col[S[top]]=numc;
ins[S[top--]]=false;
}
}
}
int op,n;
char str[20];
int ans;
bool vis1[maxn];
bool flag[maxn];
void dfs(int u){
vis1[u]=1;
for(int i=head4[u];i!=-1;i=e2[i].nxt) {if(vis1[e2[i].to]) {flag[u]=1;return;}}
for(int i=head3[u];i!=-1;i=e1[i].nxt) {dfs(e1[i].to);}
vis1[u]=0;
}
void bfs2(int u){
queue<int>q;
while(!q.empty()) q.pop();
q.push(u);
ans++;
while(!q.empty()){
u=q.front();
q.pop();
for(int i=head3[u];i!=-1;i=e1[i].nxt){
q.push(e1[i].to);
ans++;
}
}
}
int ind[maxn];
int main(){
int T;
scanf("%d",&T);
while(T--){
numc=index=ans=ecnt1=ecnt2=ecnt3=ecnt4=0;
top=0;
scanf("%d",&n);
for(int i=1;i<=n;i++){
vis1[i]=ind[i]=0;
S[i]=col[i]=0;
ins[i]=DFN[i]=LOW[i]=flag[i]=0;
head1[i]=head2[i]=head3[i]=head4[i]=-1;
}
for(int i=1;i<=n;i++){
scanf("%d%s",&op,str);
if(str[0]=='v') ins1(op,i);
else ins2(op,i);
}
for(int i=1;i<=n;i++)
if(!DFN[i]) Tarjan(i);
for(int j=1;j<=n;j++){
for(int i=head1[j];i!=-1;i=E[i].nxt){
if(col[E[i].to]!=col[j]) {ins3(col[j],col[E[i].to]);ind[col[E[i].to]]++;}
}
for(int i=head2[j];i!=-1;i=e[i].nxt){
if(col[e[i].to]!=col[j]) ins4(col[j],col[e[i].to]);
}
}
for(int i=1;i<=n;i++)
if(!ind[col[i]]) {dfs(col[i]);}
for(int i=1;i<=n;i++) if(flag[col[i]]) {bfs2(col[i]);}
printf("0 %d\n",ans);
}
return 0;
}