N个点,每个点发出一条边,那么这个图的形状一定是一个基环树森林(如果有重边就会出现森林)

那我做f[0][x]和f[1][x]分别表示对于x子树,x这个点选还是不选所带来的最大价值

然后就变成了这好几个环上不能选相邻的点,最大的价值和

我们把这个环从N到1处断开,然后钦定一下1选还是不选,统计一下答案就可以了。

 #include<bits/stdc++.h>
#define pa pair<int,int>
#define ll long long
using namespace std;
const int maxn=; inline ll rd(){
ll x=;char c=getchar();int neg=;
while(c<''||c>''){if(c=='-') neg=-;c=getchar();}
while(c>=''&&c<='') x=x*+c-'',c=getchar();
return x*neg;
} int N;
int eg[maxn*][],egh[maxn],ect;
int dep[maxn],fa[maxn];
int root[maxn][],pct,rh[maxn],rct;
int stk[maxn],top[maxn];
ll f[][maxn];
bool flag[maxn],isroot[maxn],connected[maxn]; inline void adeg(int a,int b){
eg[++ect][]=b;eg[ect][]=egh[a];egh[a]=ect;
}
inline void adrot(int a,int b){
root[++rct][]=b;root[rct][]=rh[a];rh[a]=rct;
} void dfs1(int ii,int x){
flag[x]=;
//printf("%d %d %d\n",x,fa[x],dep[x]);
for(int i=egh[x];i!=-;i=eg[i][]){
int b=eg[i][];if(b==fa[x]) continue;
//printf("#%d %d %d %d %d\n",x,b,flag[b],i,eg[i][1]);
if(flag[b]){
if(connected[ii]) continue;
int u=x,v=b,lca,cnt=;
if(dep[u]<dep[v]) swap(u,v);
while(dep[u]!=dep[v]) adrot(ii,u),isroot[u]=,u=fa[u];
while(u!=v){
isroot[u]=isroot[v]=;
adrot(ii,u);
stk[++cnt]=v;
u=fa[u];v=fa[v];
}lca=u;isroot[lca]=;adrot(ii,lca);
for(int j=cnt;j;j--) adrot(ii,stk[j]);
connected[ii]=;
}else{
dep[b]=dep[x]+;fa[b]=x;
dfs1(ii,b);
}
}
} void dfs2(int x,int F){
for(int i=egh[x];i!=-;i=eg[i][]){
int b=eg[i][];if(b==F||isroot[b]) continue;
dfs2(b,x);
f[][x]+=max(f[][b],f[][b]);
f[][x]+=f[][b];
}
} inline ll solve(int p){
if(rh[p]==-) return max(f[][top[p]],f[][top[p]]);
ll re=;
ll g1=f[][root[rh[p]][]],g0=;
for(int i=root[rh[p]][];i!=-;i=root[i][]){
ll xx=max(g0,g1);
g1=g0+f[][root[i][]];
g0=xx+f[][root[i][]];
}re=max(re,g0); g1=,g0=f[][root[rh[p]][]];
for(int i=root[rh[p]][];i!=-;i=root[i][]){
ll xx=max(g0,g1);
g1=g0+f[][root[i][]];
g0=xx+f[][root[i][]];
}re=max(re,max(g0,g1));
return re;
} int main(){
int i,j,k;
//freopen("2607.in","r",stdin);
N=rd();memset(egh,-,sizeof(egh));
for(i=;i<=N;i++){
int a=rd(),b=rd();
f[][i]=a;
adeg(i,b);adeg(b,i);
}memset(rh,-,sizeof(rh));
for(i=;i<=N;i++){
if(!flag[i]) top[++pct]=i,dfs1(pct,i);
}
//for(i=1;i<=rct;i++) printf("!%d %d %d\n",i,root[i][0],root[i][1]);
for(i=;i<=rct;i++) dfs2(root[i][],);
ll ans=;
for(i=;i<=pct;i++){
ans+=solve(i);
}
printf("%lld\n",ans); return ;
}

luogu2607/bzoj1040 [ZJOI2008]骑士 (基环树形dp)的更多相关文章

  1. [BZOJ1040][ZJOI2008]骑士 基环树DP

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1040 题目给出了$n$个点和$n$条无向边,即一棵基环树或者基环树森林. 如果题目给的关系 ...

  2. 2018.11.06 bzoj1040: [ZJOI2008]骑士(树形dp)

    传送门 由题可知给出的是基环森林. 因此对于每个基环森林找到环断开dpdpdp两次就行了. 代码: #include<bits/stdc++.h> using namespace std; ...

  3. BZOJ_1040_[ZJOI2008]骑士_树形DP

    BZOJ_1040_[ZJOI2008]骑士_树形DP 题意: Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社会各 界的赞扬.最近发生了一件可怕的事情,邪 ...

  4. [bzoj1040][ZJOI2008]骑士_树形dp_基环树_并查集

    骑士 bzoj-1040 ZJOI-2008 题目大意:n个骑士,每个骑士有权值val和一个讨厌的骑士.如果一个骑士讨厌另一个骑士那么他们将不会一起出战.问出战的骑士最大atk是多少. 注释:$1\l ...

  5. 【洛谷】2607: [ZJOI2008]骑士【树形DP】【基环树】

    P2607 [ZJOI2008]骑士 题目描述 Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社会各界的赞扬. 最近发生了一件可怕的事情,邪恶的Y国发动了一 ...

  6. BZOJ1040 [ZJOI2008]骑士 基环树林(环套树) 树形动态规划

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题意概括 有n个人,每一个人有一个最恨的人. 并且,每一个人有一个权值. 一个人不可以和他最恨的人同时被选中. 现在请你求出在 ...

  7. [ZJOI2008] 骑士 - 基环树dp

    一类基环树dp都是这个套路吧 随便拆掉环上的一条边 然后跑树形dp,设\(f[i][0/1]\)表示以第\(i\)个人为根的子树,第\(i\)个人选或不选,能收获的最大值 以断点\(u,v\)为根分别 ...

  8. [BZOJ1040][ZJOI2008]骑士(环套树dp)

    1040: [ZJOI2008]骑士 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 5816  Solved: 2263[Submit][Status ...

  9. BZOJ1040: [ZJOI2008]骑士 树套环DP

    题意:一个图n个点n条边保证点能互相到达,ab有边意味着ab互相厌恶,求一个集合,使得集合里元素最多而且没有人互相厌恶 删去环上一条边树形dp,比如删掉的边连着a,b,那么先dp出不选a的最大值,再d ...

随机推荐

  1. Google BreakPad使用集

    Google Breakpad 学习笔记 - 简书   Qt中使用Google Breakpad捕获程序崩溃异常_Linux编程_Linux公社-Linux系统门户网站 

  2. supervisord监控服务必备命令

    supervisord(http://supervisord.org/introduction.html)是一个非常优秀的进程管理工具,使用Python开发.它可以在类UNIX系统的方式让用户来准确地 ...

  3. Linux ip forward

    Linux 默认带有 ip forward 功能,只不过因为各种原因,默认的配置把该功能关闭了.本文通过 demo 来演示 Linux 的 ip forward 功能,具体场景为:开启 Linux 的 ...

  4. U盘、移动硬盘等弹出 “文件或目录损坏且无法读取” 实测解决办法

    U盘跟其他的机器一样,使用久了难免会出故障,比如常见的弹出一个文件或目录损坏且无法读取的对话框,吓你一跳,整个U盘都损坏的意思,那里面的资料怎么办呢,所以很多人很着急,其实遇到这种情况一般都是之前使用 ...

  5. 以太坊remix-ide本地环境搭建

    remix-ide简介 ​ remix-ide是一款以太坊官方solisity语言的在线IDE,可用于智能合约的编写.测试与部署,不过某些时候可能是在离线环境下工作或者受限于网速原因,使用在线remi ...

  6. C_数据结构_递归A函数调用B函数

    # include <stdio.h> int g(int); int f(int); int f(int n) { ) printf("haha\n"); else ...

  7. 《Linux内核分析》 第八节 进程的切换和一般的执行过程

    张嘉琪 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 Linux内核分析 第八 ...

  8. personal project

    words count program 统计文本文件的字符数,单词数和行数. 实现一个统计程序,他能正确的统计程序文件中的字符数,单词数和行数. 源码链接 https://github.com/sup ...

  9. 构建之法--初识Git

    该作业来自于:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE1/homework/2103 GitHub地址:https://github.com/GVic ...

  10. [转帖] testin 安全测试要点