1080. 骑士
题目链接
1080. 骑士
Z 国的骑士团是一个很有势力的组织,帮会中聚集了来自各地的精英。
他们劫富济贫,惩恶扬善,受到了社会各界的赞扬。
可是,最近发生了一件很可怕的事情:邪恶的 Y 国发起了一场针对 Z 国的侵略战争。
战火绵延五百里,在和平环境中安逸了数百年的 Z 国又怎能抵挡得住 Y 国的军队。
于是人们把所有希望都寄托在了骑士团身上,就像期待有一个真龙天子的降生,带领正义打败邪恶。
骑士团是肯定具备打败邪恶势力的能力的,但是骑士们互相之间往往有一些矛盾。
每个骑士有且仅有一个他自己最厌恶的骑士(当然不是他自己),他是绝对不会与最厌恶的人一同出征的。
战火绵延,人们生灵涂炭,组织起一个骑士军团加入战斗刻不容缓!
国王交给你了一个艰巨的任务:从所有骑士中选出一个骑士军团,使得军团内没有矛盾的两人,即不存在一个骑士与他最痛恨的人一同被选入骑士军团的情况,并且使这支骑士军团最富有战斗力。
为描述战斗力,我们将骑士按照 \(1\) 至 \(N\) 编号,给每位骑士一个战斗力的估计,一个军团的战斗力为所有骑士的战斗力之和。
输入格式
输入第一行包含一个正整数 \(N\),描述骑士团的人数;
接下来 \(N\) 行每行两个正整数,按顺序描述每一名骑士的战斗力和他最痛恨的骑士。
输出格式
输出包含一行,一个整数,表示你所选出的骑士军团的战斗力。
数据范围
\(N \le 10^6\),
每名骑士的战斗力都是不大于 \(10^6\) 的正整数。
输入样例:
3
10 2
20 3
30 1
输出样例:
30
解题思路
基环树dp
本题为树形dp 285. 没有上司的舞会 的基环树版本
删完基环上的任意一条边后即树形dp:\(f[x][0]\) 表示以 \(x\) 为根的子树不选 \(x\) 时的最大值,\(f[x][1]\) 表示以 \(x\) 为根的子树选 \(x\) 时的最大值
考虑环上的任意一条边:\(x\rightarrow y\),对于 \(x\) 来说只有两种情况:选或不选,不选 \(x\) 时可以直接删除这条边,即对于跟 \(x\) 有关系的边的其他点可选可不选,这部分贡献为 \(f[x][0]\),选择 \(x\) 则 \(y\) 不能选,进行树形dp 时特判一下即可,注意这时不用考虑删完这条边那些与 \(x\) 有关系的边,因为此时 \(x\) 必选,要求的是 \(f[x][1]\),转移时已经考虑到了
- 时间复杂度:\(O(n)\)
代码
// Problem: 骑士
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/1082/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=1e6+6;
int n;
int h[N],e[N],ne[N],idx,w[N];
LL f1[N][2],f2[N][2],res;
bool st[N],in[N],rm[N];
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int x,int u,LL f[][2])
{
f[x][1]=-0x3f3f3f3f;
if(x!=u)f[x][1]=w[x];
for(int i=h[x];~i;i=ne[i])
{
if(rm[i])continue;
int y=e[i];
dfs(y,u,f);
f[x][0]+=max(f[y][0],f[y][1]);
f[x][1]+=f[y][0];
}
}
void dfs_c(int x)
{
st[x]=in[x]=true;
for(int i=h[x];~i;i=ne[i])
{
int y=e[i];
if(!st[y])dfs_c(y);
else if(in[y])
{
rm[i]=true;
dfs(y,-1,f1);
dfs(y,x,f2);
res+=max(f1[y][0],f2[y][1]);
}
}
in[x]=false;
}
int main()
{
memset(h,-1,sizeof h);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int a;
scanf("%d%d",&w[i],&a);
add(a,i);
}
for(int i=1;i<=n;i++)
if(!st[i])dfs_c(i);
printf("%lld",res);
return 0;
}