骑士 树上+环上dp

这题我最大的收获是不要轻易相信网上的blog的题解...

环上dp 应该是两维,不能一维 (一下午的崩溃啊)

先求出环上每个点选和不选的最大值

再枚举环上那个点选不选(枚举相邻两个就行)

进行dp

/*
我现在只想日死那个一维f[]的人
环上dp需要f[N][2]...
 */
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <queue>
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
inline int read()
{
    char q=getchar();int ans=0,flag=1;
    while(q<'0'||q>'9'){if(q=='-')flag=-1;q=getchar();}
    while(q>='0'&&q<='9'){ans=ans*10+q-'0';q=getchar();}
    return ans*flag;
}
const int N=1000006;
inline ll maxn(ll a,ll b){return a>b?a:b;}
struct son
{
    int v,next;
}a1[N*2];
int first[N*2],e;
void addbian(int u,int v)
{
    a1[e].v=v;
    a1[e].next=first[u];
    first[u]=e++;
}

int n;
int nx[N],ind[N];
int v[N];
ll g[N][2];
int dfn[N],low[N],zhan[N],he,tim,dui[N],sum,size[N];
bool flag[N];
bool vis[N];

ll t[N][2];
int con;
ll f[N][2];

ll get(int begg,int endd)
{
    con=0;
    for(int i=begg;i!=endd;i=nx[i])
    {
        ++con;
        vis[i]=1;
        t[con][0]=g[i][0];
        t[con][1]=g[i][1];
    }
    f[0][0]=f[0][1]=0;
    f[1][0]=t[1][0];f[1][1]=t[1][1];
    for(int i=2;i<=con;++i)
    {
        f[i][1]=f[i-1][0]+t[i][1];
        f[i][0]=maxn(f[i-1][1],f[i-1][0])+t[i][0];
    }
    return maxn(f[con][0],f[con][1]);
}

int fa[N];
void dp(int x)
{
    g[x][0]=0;g[x][1]=v[x];
    int temp;
    for(int i=first[x];i!=-1;i=a1[i].next)
    {
        temp=a1[i].v;
        if(temp==fa[x]||size[dui[temp]]>1)
            continue;
        fa[temp]=x;
        dp(temp);
        g[x][0]+=maxn(g[temp][0],g[temp][1]);
        g[x][1]+=g[temp][0];
    }
}

void tarjan(int x)
{
    dfn[x]=low[x]=++tim;
    zhan[++he]=x;flag[x]=1;
    int temp;
    for(int i=first[x];i!=-1;i=a1[i].next)
    {
        temp=a1[i].v;
        if(dfn[temp]==-1)
        {
            tarjan(temp);
            low[x]=min(low[x],low[temp]);
        }
        else
            if(flag[temp])
                low[x]=min(low[x],low[temp]);
    }
    if(low[x]==dfn[x])
    {
        ++sum;
        while(1)
        {
            temp=zhan[he--];flag[temp]=0;
            dui[temp]=sum;
            ++size[sum];
            if(temp==x)
                break;
        }
    }
}

ll work()
{
    ll ans=0,t1,t2;

    he=0;
    for(int i=1;i<=n;++i)
        if(dfn[i]==-1)
            tarjan(i);

    for(int i=1;i<=n;++i)
        if(size[dui[i]]>1)
        {
            fa[i]=-1;
            dp(i);
        }

    for(int i=1;i<=n;++i)
        if(size[dui[i]]>1&&!vis[i])
        {
            t1=g[i][0]+get(nx[i],i);
            t2=g[nx[i]][0]+get(nx[nx[i]],nx[i]);
            ans+=maxn(t1,t2);
        }
    return ans;
}

int main(){

    //freopen("in.in","r",stdin);

    mem(first,-1);
    mem(dfn,-1);

    scanf("%d",&n);
    for(int i=1;i<=n;++i)
    {
        scanf("%d%d",&v[i],&nx[i]);
        ++ind[nx[i]];
        addbian(nx[i],i);
    }
    cout<<work();
}
AA

本来还觉得这道题跟maf枪战一样呢

还应用了贪心+一些之前做过的题的技巧,打了半天wa了6个点....

posted @ 2017-10-15 19:06  A_LEAF  阅读(176)  评论(0编辑  收藏  举报