HDU 6370 Werewolf 思維,基環樹.
阿新 • • 發佈:2018-11-02
題意:村民只會說真話,狼可能說假話. (i,j,k)表示第i個人說第j個人是k(k=村民或者狼)[i=1..n].i!=j.
n<=1e5.總共有2^n種情景(有些可能非法.). 問有多少人一定為村民,以及有多少人一定為狼?
因為狼可以將真話也可以講假話. 假如n個人全部為狼,不會產生任何矛盾,
第i人說其他人為村民就當做假話,說別人為狼就當做真話.所以一定為村民的人數為0.
先不考慮狼邊(第i個人說第j個人為狼.),則原圖分成若干個聯通分量.
因為每個點只有一個出邊, 連通分量有兩種,n點n條邊的基環樹, n點n-1條邊的樹.
基環樹的人為村民不會有任何矛盾.
對於第二種聯通分量,發現缺邊的是樹根.
若連的是其他聯通分量,那麼這顆樹顯然都可以當村民.
否則連的是自己的某個子孫.
此時若根為狼,那麼整個樹都為狼,
若根為村民,那麼根的出邊值值向x時,村民只說真話,x為狼,那麼子樹x說x為村民為謊話,子樹x都為狼.
所以無論怎樣.子樹x一定為狼.
因為只要求肯定為狼的個數,那麼反向建樹,求出每個子樹的大小,以及狼邊是否連的是自己的子樹.
#include <bits/stdc++.h> using namespace std; const int N=2e5+5; int T,n,x,a[N],fa[N],sz[N],in[N]; vector<int> e[N]; void dfs(int u,int rt){ sz[u]=1; for(int i=0;i<e[u].size();i++){ int v=e[u][i]; fa[v]=rt; dfs(v,rt); sz[u]+=sz[v]; } } int main(){ ios::sync_with_stdio(false);cin.tie(0); cin>>T; while(T--){ cin>>n; for(int i=1;i<=n;i++) e[i].clear(),fa[i]=i,in[i]=0,a[i]=0; string s; for(int i=1;i<=n;i++){ cin>>x>>s; if(s=="werewolf") a[i]=x; else{ //(i,x) .in[u]==0 -> u真正出邊為狼邊. u為根. in[i]++; e[x].push_back(i); } } for(int i=1;i<=n;i++) if(!in[i]) dfs(i,i); int res=0; for(int i=1;i<=n;i++){ if(in[i]|| fa[a[i]]!=i) continue; res+=sz[a[i]]; } cout<<0<<' '<<res<<'\n'; } return 0; }