[P2607 [ZJOI2008] 骑士 - 洛谷](https://www.luogu.com.cn/problem/P2607)
题目连接加上标题
P2607 [ZJOI2008] 骑士 - 洛谷
题目大意(自己总结
给定n个骑士最讨厌的人,和他的战力,组成一个军团,且该骑士不能和他讨厌的人在一个军团
题目主要实现思路
因为每个骑士只有一个最讨厌的人,一个骑士只能讨厌一个人,但是可以被多个骑士讨厌,就是多对1可以建反图,由于每个骑士出度为1,且n个点n条边,则一定是基环树或者基环树森林,首先对于每一个连通块找到u1和u2,如果找到了,就是一个树形dp,上司的舞会模型,如果没有找到也不要进入树形dp因为很有可能找到得不是根节点,跳过即可,另外注意找到环不能用单纯的vit这个只能判环不能找到环上的两个点
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6 + 10;
const int mod = 998244353;
int u1 = 0, u2 = 0;
int vit[N];
int dp[N][2];
void solve()
{
int n;
cin >> n;
vector<int> w(n + 1);
vector<vector<int>> adj(n + 1);
for (int i = 1; i <= n; i++)
{
int v;
cin >> w[i] >> v;
adj[v].push_back(i);
}
auto dfs = [&](auto &&self, int u, int rt) -> void
{
vit[u] = 1;
for (int &nu : adj[u])
{
if (nu == rt)//只有从一个点到了另一个点,才能确定这两个点在环上
{
u1 = rt;
u2 = u;
return;
}
self(self, nu, rt);
}
};
auto dop = [&](auto &&self, int u, int s) -> void
{
dp[u][0] = 0;
dp[u][1] = w[u];
for (auto &nu : adj[u])
{
if (nu == s)
{
continue;
}
self(self, nu, s);
dp[u][0] += max(dp[nu][1], dp[nu][0]);
dp[u][1] += dp[nu][0];
}
};
int ans = 0;
for (int i = 1; i <= n; i++)
{
u1=0,u2=0;
if (!vit[i])
{
dfs(dfs, i, i);
if (u1)//如果没找到有可能不是根节点
{
dop(dop, u1, u1);
int res1 = dp[u1][0];
dop(dop, u2, u2);
ans += max(res1, dp[u2][0]);
}
}
}
cout << ans << '\n';
}
signed main()
{
ios::sync_with_stdio(0), cin.tie(0);
cout.tie(0);
int T;
T = 1;
// cin >> T;
while (T--)
solve();
return 0;
}

浙公网安备 33010602011771号