ZJOI2008骑士[树形dp]

Posted lxyyyy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ZJOI2008骑士[树形dp]相关的知识,希望对你有一定的参考价值。

[ZJOI2008]骑士
很容易就能想到将一个骑士不喜欢的骑士设为他的父亲 每一个骑士只有一个讨厌的人 那么它的入度只能为1
所以对于每个连通块 它一定有且只有一个包含根节点的环
所以将环拆开 第一遍dp为不选它的父亲 第二遍dp为不选它的父亲的父亲
(其实我也不太明白为啥这么搞)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rg register
#define Max(x,y) ((x)>(y)?(x):(y))
#define Min(x,y) ((x)>(y)?(y):(x))
const int N=1e6+5,M=2e5+5,inf=0x3f3f3f3f,P=19650827;
int n,a[N],ene[N],rt;
bool vis[N];
ll f[N][2],ans=0;
template <class t>void rd(t &x)
    x=0;int w=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x=w?-x:x;


int head[N],tot=0;
struct edgeint v,nxt;e[N];
void add(int u,int v)
    e[++tot]=(edge)v,head[u],head[u]=tot;


void dfs(int u)
    vis[u]=1,f[u][0]=0,f[u][1]=a[u];//因为要跑两次 
    for(int i=head[u],v;i;i=e[i].nxt)
        v=e[i].v;
        if(v!=rt) dfs(v),f[u][0]+=Max(f[v][0],f[v][1]),f[u][1]+=f[v][0];
        else f[u][1]=-inf;
    


void find(int x)
    vis[x]=1,rt=x;
    while(!vis[ene[rt]]) rt=ene[rt],vis[rt]=1;
    dfs(rt);//一定不选根节点父亲
    ll ret=Max(f[rt][0],f[rt][1]);
    rt=ene[rt];
    dfs(rt);//一定不选根节点父亲的父亲 
    ans+=Max(ret,Max(f[rt][0],f[rt][1]));


int main()
    freopen("in2.txt","r",stdin);
    //freopen("xor.out","w",stdout);
    rd(n);
    memset(f,0,sizeof(f));
    for(int i=1,x;i<=n;++i)
    rd(a[i]),rd(x),add(x,i),ene[i]=x;
    for(int i=1;i<=n;++i)//有多个连通块 
    if(!vis[i]) find(i);
    printf("%lld",ans);
    return 0;

以上是关于ZJOI2008骑士[树形dp]的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ_1040_[ZJOI2008]骑士_树形DP

bzoj1040骑士[ZJOI2008](树形dp)

[ZJOI2008]骑士(基环树,树形dp)

bzoj1040: [ZJOI2008]骑士(基环树+树形dp)

BZOJ1040[ZJOI2008]骑士 树形DP

BZOJ 1040 ZJOI2008 骑士 树形DP