Werewolf
H.Werewolf
题意是:狼人杀,然后放逐投票的时候,每个人可以投一个对象,只有狼和好人之分,狼不能投狼,好人可以投好人也可以投狼,给出每个人投票的对象,问说最多能有多少头狼。
把n个人看成n个点,然后建图,最后的图肯定是一个由k个联通分块组成的,每个连通块里面是一棵树或者一棵树再加一条边。如果没有这条边我们直接树形dp就行了,但是我们可以先把这条边去掉,然后我们可以分两种情况进行讨论,1、被多余的那条边连接的那两个点只有一个点被选取了的情况;2、这两个点都不被选取;
按照上面两种情况,做三次dp,就可以得到正确的答案了
#include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<time.h>
#include<cstdio>
#include<vector>
#include<stack>
#include<queue>
#include<iostream>
using namespace std;
#define LONG long long
const int INF=0x3f3f3f3f;
const LONG MOD=1e9+7;
const double PI=acos(-1.0);
#define clr0(x) memset(x,0,sizeof x)
#define clrI(x) memset(x,-1,sizeof(x))
#define clr1(x) memset(x,INF,sizeof x)
#define clr2(x) memset(x,-INF,sizeof x)
#define EPS 1e-10
const int MAXN = 1e6 + 100 ;
struct Edge
{
int u, to , next ;
}edge[MAXN<<2];
int n ;
int tot = 0 ;
int head[MAXN<<2] ;
int fa[500500] ;
int take[500500] ;
int Qd1 , Qd2 ;
int vis [500500] ;
int dp[500050][2] ;
int root[500500] ;
int Pre[500500] ;
int judge ;
int Rjudge ;
int Find(int x)
{
vis[x] ++ ;
if(vis[fa[x]] ) return fa[x] = fa[fa[x]];
if (x == fa[x]) return x;
return fa[x] = Find(fa[x]) ;
}
void Add(int u , int v)
{
edge[++tot].to = v ;
edge[tot].u = u;
edge[tot].next = head[u] ;
head[u] = tot ;
}
void Init()
{
tot = 0 ;
clrI(head) ;
clr0(take) ;
clr0(dp) ;
clr0(vis) ;
}
void Found(int pre , int u)
{
vis[u] ++ ;
int t = 0;
for(int i = head[u] ; i != -1 ; i = edge[i].next)
{
int v = edge[i].to ;
if(v == pre )
{
t ++ ;
if(t >= 2) Rjudge = 1;
continue ;
}
if(vis[v])
{
Qd1 = v ;
Qd2 = u ;
continue ;
}
Found( u , v ) ;
}
}
void dfs(int pre ,int u)
{
dp[u][1] += 1;
vis[u] ++ ;
for(int i = head[u] ; i != -1 ; i = edge[i].next)
{
int v = edge[i].to ;
if(v == pre) continue ;
if(vis[v] )
continue ;
dfs(u , v) ;
if( v == Qd1 && judge == 0 )
{
dp[u][0] += dp[v][1] ;
dp[u][1] += 0 ;
}
else if(v == Qd2 && judge == 0)
{
dp[u][0] += dp[v][0] ;
dp[u][1] += dp[v][0] ;
}
else if(v == Qd1 && judge == 1)
{
dp[u][0] += dp[v][0] ;
dp[u][1] += dp[v][0] ;
}
else if(v == Qd2 && judge ==1 )
{
dp[u][0] += dp[v][1] ;
dp[u][1] += 0;
}
else if(v == Qd1 && judge == 2)
{
dp[u][0] += dp[v][0] ;
dp[u][1] += dp[v][0] ;
}
else if(v == Qd2 && judge == 2)
{
dp[u][0] += dp[v][0] ;
dp[u][1] += dp[v][0] ;
}
else
{
dp[u][0] += max(dp[v][0] , dp[v][1] ) ;
dp[u][1] += dp[v][0] ;
}
}
// printf("%d %d %d\n",u,dp[u][0],dp[u][1]);
}
int main()
{
// freopen("C:\\Users\\ZhangYuyang\\Desktop\\in.txt","r",stdin);
//freopen("C:\\Users\\ZhangYuyang\\Desktop\\out2.txt","w",stdout);
while(cin >> n)
{
Init() ;
for(int i = 1; i<= n ; ++ i)
fa[i] = i ;
int v ;
for(int i = 1; i<= n ;++i)
scanf("%d",&v) ,
Add( i , v ) ,
Add( v , i ) ,
fa[i] = v;
for(int i = 1; i <= n ;++i) if(!vis[i])fa[i] = Find(i) ;
for(int i = 1 ; i <= n ;++i) fa[i] = Find(i) ,take[fa[i]] = 1;
int ans = 0 ;
clr0(vis) ;
for(int i = 1; i<= n ;++ i)
{
if(take[i] == 0) continue ;
Rjudge = 0 ;
judge = -1 ;
int tmp = 0 ;
Qd1 = -1 , Qd2 = -1;
Found( -1 , i ) ;
if(Rjudge)
{
clr0(vis) ;
dfs(-1 , i ) ;
tmp = max(dp[i][0] , dp[i][1] ) ;
ans += tmp ;
}
else
{
judge ++ ;
clr0(vis) ;
dfs( -1 , i ) ;
if(Qd2 != i)
tmp = max(dp[i][0] , dp[i][1] ) ;
else tmp = dp[i][0] ;
clr0(dp) ;
clr0(vis) ;
judge ++ ;
dfs(-1 , i );
if(Qd1 != i)
tmp = max(max(dp [i][0] , dp[i][1]) , tmp ) ;
else
tmp = max(tmp , dp[i][0]) ;
judge ++ ;
clr0(dp) ;
clr0(vis) ;
dfs(-1, i) ;
tmp = max(tmp , max(dp[i][0] , dp[i][1]) ) ;
ans += tmp ;
}
// printf("%d %d\n",Qd1,Qd2);
}
cout<<ans<<endl;
}
}