bzoj1040: [ZJOI2008]骑士

本来今天想学基环树的

认真看一看,这不就是弱化的仙人掌嘛

然后,就直接仙人掌上DP咯(蒟蒻不是很会调了一晚上。。。)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;

struct node
{
    int x,y,next;
}a[2100000];int len,last[1100000];
void ins(int x,int y)
{
    len++;
    a[len].x=x;a[len].y=y;
    a[len].next=last[x];last[x]=len;
}
LL ft[1100000],f[2][1100000];
int z,dfn[1100000],fa[1100000];
bool v[1100000];//是否在仙人掌中
void DP(int rt,int x)//只需要更新rt 
{
    LL g[2][2];
    int pre=0,now=1;
    g[now][0]=g[now][1]=0;
    for(int i=x;i!=rt;i=fa[i])
    {
        swap(pre,now);
        g[now][0]=max(g[pre][0],g[pre][1])+f[0][i];
        g[now][1]=g[pre][0]+f[1][i];
    }
    f[0][rt]+=max(g[now][0],g[now][1]);
    //不取rt 
    
    pre=0,now=1;
    g[now][0]=g[now][1]=0;
    for(int i=x;i!=rt;i=fa[i])
    {
        swap(pre,now);
        g[now][0]=max(g[pre][0],g[pre][1])+f[0][i];
        if(i==x||fa[i]==rt)g[now][1]=0;
        else g[now][1]=g[pre][0]+f[1][i];
    }
    f[1][rt]+=max(g[now][0],g[now][1]);
    //取rt 
}
int h[1100000];
void cactus(int x)
{
    dfn[x]=++z;
    f[0][x]=0;f[1][x]=ft[x];
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(dfn[y]==0)
            fa[y]=x, cactus(y);
    }
    
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(fa[x]!=y)
        {
            if(dfn[y]<dfn[x])
            {
                h[y]=x;
                for(int i=x;i!=y;i=fa[i])v[i]=true;
            }
            else if(v[y]==false)
            {
                f[0][x]+=max(f[0][y],f[1][y]);
                f[1][x]+=f[0][y];
            }
        }
    }
    if(h[x]!=-1)DP(x,h[x]);
}

//-------------------------------

int hate[1100000];
int main()
{
    int n,x;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld%d",&ft[i],&x);
        hate[i]=x;
        if(hate[x]!=i)
            ins(i,x), ins(x,i);
    }
    
    LL ans=0;
    memset(dfn,0,sizeof(dfn));
    memset(v,false,sizeof(v));
    memset(h,-1,sizeof(h));
    for(int i=1;i<=n;i++)
        if(dfn[i]==0)
        {
            cactus(i);
            ans+=max(f[0][i],f[1][i]);
        }
    printf("%lld
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/AKCqhzdy/p/8886249.html