新千题计划 5#:[ZJOI08] 骑士

骑士 给一点权基环树森林,每个点和其出度不同选,求选出点权和之最大值。

树上 DP。 按基环树的套路先判环,尔后从成环点及其父节点出发分别舞会1,并取最大值相加。但有两个坑点:标注 What Ghost 处一句不能略,因为 cc[in][1] 状态无效;std::vector 存图会卡一个点。

#include <cstdio>
#include <algorithm>
#define F(z, u, v) for(int z = (u), zz = (v); z <= zz; z++)
typedef long long int LINT;
const int MAXN = 1000001;
int n, w[MAXN], pa[MAXN]; bool vis[MAXN]; LINT ans = 0;
int hd[MAXN], po[MAXN];

LINT Dfs(int cr, int in) { 
 static LINT cc[MAXN][2];
 vis[cr] = true; cc[cr][0] = 0; cc[cr][1] = w[cr];
 for(int i = hd[cr]; i; i = po[i])
  if(i != in) { Dfs(i, in);
  cc[cr][0] += std::max(cc[i][0], cc[i][1]); cc[cr][1] += cc[i][0]; }
  else cc[in][1] = -MAXN; // What ghost?!
 return std::max(cc[cr][0], cc[cr][1]); }

int main() {
 scanf("%d", &n);
 F(i, 1, n) { scanf("%d%d", w + i, pa + i);
  po[i] = hd[pa[i]]; hd[pa[i]] = i; }
 F(i, 1, n) if(!vis[i]) for(int j = i;; j = pa[j]) {
  vis[j] = true; if(vis[pa[j]]) {
  ans += std::max(Dfs(j, j), Dfs(pa[j], pa[j])); break; }}
 printf("%lld", ans); }

  1. “没有上司的舞会”问题,转移方程为 dp[i][0]=kson(i)maxdp[k][0],dp[k][1],dp[i][1]=kson(i)dp[k][0] d p [ i ] [ 0 ] = ∑ k ∈ s o n ( i ) max d p [ k ] [ 0 ] , d p [ k ] [ 1 ] , d p [ i ] [ 1 ] = ∑ k ∈ s o n ( i ) d p [ k ] [ 0 ]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值