ZJOI2008 骑士

Posted liguanlin1124

tags:

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

题目描述:

bz

luogu

题解:

基环树+树形$dp$。

每次找到一个联通块,对于环上的每个点向树的方向做树形$dp$。

即$dp[i][0/1]$表示$i$点取/不取,$i$点子树内最大权。

$pj$难度?

然后拆环$dp$,讨论第一个点取还是不取。

代码:

技术图片
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 1000050;
template<typename T>
inline void read(T&x)
{
    T f = 1,c = 0;char ch=getchar();
    while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}
    while(ch>=0&&ch<=9){c=c*10+ch-0;ch=getchar();}
    x = f*c;
}
int n,hed[N],cnt=1;
ll w[N];
bool use[N];
struct EG
{
    int to,nxt;
}e[2*N];
void ae(int f,int t)
{
    e[++cnt].to = t;
    e[cnt].nxt = hed[f];
    hed[f] = cnt;
}
void bfs(int rt)
{
    queue<int>q;
    q.push(rt);
    use[rt] = 1;
    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        for(int j=hed[u];j;j=e[j].nxt)
        {
            int to = e[j].to;
            if(!use[to])
            {
                use[to] = 1;
                q.push(to);
            }
        }
    }
}
int sta[N],tl,rt;
bool vis[N],cir[N];
int dfs0(int u,int pre)
{
    if(vis[u]){rt=u;return 1;}
    vis[u] = 1;
    for(int j=hed[u],now;j;j=e[j].nxt)
    {
        int to = e[j].to;
        if(j==pre)continue;
        if((now=dfs0(to,j^1)))
        {
            if(now==1)
            {
                sta[++tl] = u;
                cir[u] = 1;
                if(u!=rt)return 1;
            }
            return 2;
        }
    }
    return 0;
}
ll dp[N][2],s[N][2];
void dfs(int u,int f)
{
    dp[u][0] = 0,dp[u][1] = w[u];
    for(int j=hed[u];j;j=e[j].nxt)
    {
        int to = e[j].to;
        if(to==f||cir[to])continue;
        dfs(to,u);
        dp[u][0]+=max(dp[to][0],dp[to][1]);
        dp[u][1]+=dp[to][0];
    }
}
ll sol(int z)
{
    s[1][0]=dp[sta[1]][0],s[1][1]=(z?dp[sta[1]][1]:0);
    for(int i=2;i<=tl;i++)
    {
        s[i][0]=dp[sta[i]][0]+max(s[i-1][0],s[i-1][1]);
        s[i][1]=dp[sta[i]][1]+s[i-1][0];
    }
    return z?s[tl][0]:max(s[tl][0],s[tl][1]);
}
int main()
{
//    freopen("tt.in","r",stdin);
    read(n);
    for(int i=1,f;i<=n;i++)
    {
        read(w[i]),read(f);
        ae(f,i),ae(i,f);
    }
    ll ans = 0;
    for(int i=1;i<=n;i++)if(!use[i])
    {
        bfs(i);tl=0;
        dfs0(i,0);
        for(int j=1;j<=tl;j++)dfs(sta[j],0);
        ans+=max(sol(0),sol(1));
    }
    printf("%lld\n",ans);
    return 0;
}
View Code

 

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

[ZJOI2008]骑士

BZOJ 1040: [ZJOI2008]骑士

bzoj1040[ZJOI2008]骑士

BZOJ1040: [ZJOI2008]骑士

ZJOI2008骑士[树形dp]

bzoj 1040 1040: [ZJOI2008]骑士