【BZOJ1006】神奇的国度
【BZOJ4196】软件包管理器

【BZOJ1040】骑士

Zarxdy34 posted @ 2015年11月26日 19:38 in BZOJ with tags 树形DP , 579 阅读

    带一个环的树,把环上两个相邻的点u,v之间的一条边切掉(有两条就只切一条),考虑取u不取v,不取u随意取不取v两种状态,然后做树形dp。

 

 

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn=1000010;
 
int head[maxn],next[maxn<<1],E[maxn<<1],Ecnt;
int v[maxn];
int n;
 
void read(int &x) {char ch;while ((ch=getchar())<'0' || ch>'9');x=ch-'0';while ((ch=getchar())<='9' && ch>='0') x=x*10+ch-'0';}
void Add_Edge(int x,int y) {next[++Ecnt]=head[x];head[x]=Ecnt;E[Ecnt]=y;next[++Ecnt]=head[y];head[y]=Ecnt;E[Ecnt]=x;}
 
int vis[maxn];
int FindC;
int pu,pv,pe,cu;
LL f[maxn][2];
LL ans;
 
void Find_Circle(int x,int qe)
{
    vis[x]=1;
    for (int i=head[x];i;i=next[i]) if (i!=(qe^1))
        if (vis[E[i]])
        {
            FindC=1;
            pu=x;pv=E[i];
            pe=i;
            return;
        }
        else
        {
            Find_Circle(E[i],i);
            if (FindC==1) return;
        }
}
 
void DFS(int x,int fa)
{
    vis[x]=1;
    if (x!=pu) f[x][0]=f[x][1]=0;
    if (x==pu)
    {
        if (cu==1) f[x][1]=v[x];
        for (int i=head[x];i;i=next[i]) if (E[i]!=fa && (i>>1)!=(pe>>1))
        {
            DFS(E[i],x);
            if (cu==0) f[x][0]+=max(f[E[i]][0],f[E[i]][1]);
            if (cu==1) f[x][1]+=f[E[i]][0];
        }
        return;
    }
    if (x==pv)
    {
        if (cu==0) f[x][1]=v[x];
        for (int i=head[x];i;i=next[i]) if (E[i]!=fa && (i>>1)!=(pe>>1))
        {
            DFS(E[i],x);
            f[x][0]+=max(f[E[i]][0],f[E[i]][1]);
            if (cu==0) f[x][1]+=f[E[i]][0];
        }
        return;
    }
    f[x][1]=v[x];
    for (int i=head[x];i;i=next[i]) if (E[i]!=fa)
    {
        DFS(E[i],x);
        f[x][1]+=f[E[i]][0];
        f[x][0]+=max(f[E[i]][1],f[E[i]][0]);
    }
}
 
LL Work(int x)
{
    FindC=0;
    Find_Circle(x,0);
    cu=0;
    DFS(pu,0);
    cu=1;
    DFS(pu,0);
    return max(f[pu][0],f[pu][1]);
}
 
int main()
{
    read(n);
    Ecnt=1;
    for (int i=1,y;i<=n;i++) 
        read(v[i]),read(y),Add_Edge(i,y);
    for (int i=1;i<=n;i++) if (!vis[i]) ans+=Work(i);
    printf("%lld\n",ans);
    return 0;
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter