把图画一画可以发现只能判断铁狼,没有确定的村民,铁狼会存在于一个环中,这个环里面如果只有一个人被认为是狼,那么他就是铁狼,可以很容易看出这是一个基环内向树的样子,所以就会发现,如果还有人说这个铁狼是村民的话,那说这个狼是村民的人就是狼。于是就可以想到有些环是没有用的环,如果有一个环上的边都是村民边,那这个环没有卵用,直接缩掉。至于如何搜答案,可以很快想到先确定环上的狼,然后向外扩展,于是就可以反向建图,这时就是一个基环外向树的图,并且如果只加村民边的话,就形成了一个树的样子(虽然有向图这么说很不严谨,但是想不到怎么描述),并且每个点的入度最大为1,这样就可以比较方便地暴力。(爆栈,改掉了一个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;
}