正题
题目大意
每个骑士有一个不可以同时上场的骑士,和一个战斗力。求最大战斗力。
解题思路
类似没有上司的舞会
其实就是在基环树森林,我们可以利用二次树形dp的方法。
先找到环,然后强行将环断开进行一次dp,然后强行连上进行一次dp,两次答案求最大值。
code
#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
#define N 1000010
using namespace std;
struct node{ll to,next;
}a[N];
ll w[N],n,x,ans,tot,fa[N],root,f[N],g[N],ls[N],d[N],mark;
bool v[N];
void addl(ll x,ll y)//连边
{a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;
}
void check_c(ll x)//找环
{v[x]=true;if(v[d[x]]) mark=x;else check_c(d[x]);return;
}
void dp(ll x)//树形dp
{v[x]=true;f[x]=w[x];g[x]=0;for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;if(y!=mark)//如果是断开就不选{dp(y);g[x]+=max(f[y],g[y]);f[x]+=g[y];}else f[y]=-2147483647/3;}return;
}
int main()
{scanf("%lld",&n);for(ll i=1;i<=n;i++)scanf("%lld%lld",&w[i],&d[i]),addl(d[i],i);for(ll i=1;i<=n;i++){if(v[i]) continue;check_c(i);dp(mark);ll maxs=max(f[mark],g[mark]);mark=d[mark];root=0;dp(mark);ans+=max(maxs,max(f[mark],g[mark]));}printf("%lld",ans);
}