题目链接:https://cn.vjudge.net/contest/246776#problem/E
题目大意:每个骑士都有自己厌恶的人和自己的战斗力,求一个军队中每一个人所厌恶的人都不在,军团战斗力为所有骑士战斗力的和,问军团的战斗力最大为多少。
思路:https://blog.csdn.net/qq_36782366/article/details/81674459
和没有上司的舞会类似。只是多了一个环。
因此我们先要找到树上的环,任何删除任意环上的一条边,加上删的这条边的两个端点为i,j。
接下来就要以i和j为根结点分别跑一边,因为i和j的状态有3种,i选j不选,i不选j选,i和j都不选。所以检测一下哪种情况的战斗力最大。
注意输入的是基环森林,不一定都在一棵树上。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 1e6+100;
int n,a[MAXN],cnt,l,r,edgenum;
int head[MAXN];
bool vis[MAXN];
ll dp[MAXN][2];
struct Edge
{
int to,nex;
}edge[MAXN*2];
void addedge(int u,int v)
{
edge[cnt] = {v,head[u]};
head[u] = cnt++;
edge[cnt] = {u,head[v]};
head[v] = cnt++;
}
void loop(int u,int fa)
{
for (int i=head[u];~i;i=edge[i].nex)
{
int v = edge[i].to;
if (v == fa) continue;
if (!vis[v])
{
vis[v] = true;
loop(v,u);
}
else
{
edgenum = i;
l = u; r = v;
}
}
}
void dfs(int u,int fa)
{
dp[u][0] = 0;
dp[u][1] = a[u];
for (int i=head[u];~i;i=edge[i].nex)
{
int v = edge[i].to;
if ( v == fa || ((i^1) == edgenum) || i == edgenum ) continue;
dfs(v,u);
dp[u][1] += dp[v][0];
dp[u][0] += max( dp[v][1], dp[v][0] );
}
}
int main()
{
memset(head,-1,sizeof head);
scanf("%d",&n);
cnt=0;
for (int i=1;i<=n;i++)
{
int to;
scanf("%d%d",&a[i],&to);
addedge( i,to );
}
ll ans = 0;
for (int i=1;i<=n;i++)
{
if (vis[i]) continue;
loop(i,0);
dfs(l,0);
ll tmp = dp[l][0];
dfs(r,0);
ans += max(tmp, dp[r][0]);
}
printf("%lld\n",ans);
return 0;
}