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;
}
posted @ 2022-10-13 18:21  zyy2001  阅读(18)  评论(0编辑  收藏  举报