码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj 1040: [ZJOI2008]骑士

时间:2019-01-12 19:00:11      阅读:164      评论:0      收藏:0      [点我收藏+]

标签:print   ons   不同   位运算   mes   main   eof   scanf   ted   

 

 和仙人掌有所不同? 应该是一样的啊。。。

 

/**************************************************************
    Problem: 1040
    User: lxy8584099
    Language: C++
    Result: Accepted
    Time:1916 ms
    Memory:40868 kb
****************************************************************/
 
// by pig~~
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
/*
    思路:
    因为每个人只有一个特别讨厌的人 所以建边后 肯定成环或者是单独一个点(看作环)
    对每个环进行DP 每次DP后最大值累加起来 
*/
const int N=1000050;
struct pp{int nxt,to;}e[N<<1];
int n,tot,val[N],head[N],u1,u2,E;
ll ans,f[N][2];// f[i][0/1]  表示 不取/取  这个点的最大值 
bool vis[N];
inline void add(int u,int v){e[tot].nxt=head[u];e[tot].to=v;head[u]=tot++;}
inline ll max(ll a,ll b){return a>b?a:b;}
inline ll min(ll a,ll b){return a>b?b:a;}
inline void dfs(int u,int last)  
{
    vis[u]=1;
    for(int j=head[u];~j;j=e[j].nxt)
    {
        if((j^1)==last) continue; // 去掉返回边,不走回头路 
        int v=e[j].to;
        if(vis[v])
        {
            u1=u;u2=v;E=j;continue; // 找到环  选择切断的边 E,俩断点 u1,u2  
        }
        dfs(v,j);
    }
}
inline void DP(int u,int last)
{
    f[u][0]=0;f[u][1]=val[u];
    for(int j=head[u];~j;j=e[j].nxt)
    {
        if(((j^1)==last)||(j==E)||((j^1)==E)) continue; // 去掉返回边,不走我们选择断掉的路 
        int v=e[j].to;
        DP(v,j);
        f[u][1]+=f[v][0];
        f[u][0]+=max(f[v][1],f[v][0]);
    }
}
int main()
{
//    freopen("knight.in","r",stdin);
//    freopen("knight.out","w",stdout);
    memset(head,-1,sizeof(head));
    scanf("%d",&n);
    for(int i=1,v;i<=n;i++)
    {
        scanf("%d%d",&val[i],&v);add(i,v);add(v,i);//建边 从0开始 用位运算方便求出同边 
    }
    for(int i=1;i<=n;i++) 
    {
        if(vis[i]) continue;
        dfs(i,-2);ll all;
        /*
            本次DP的答案在f[u1][0] 或 f[u2][0] 中
            因为f[u1][1]的结果可能会包含取到 u2 ,
            同理 f[u2][1]的结果可能会包含取到 u1. 
        */
        DP(u1,-1);
        all=f[u1][0];
        DP(u2,-1);
        all=max(all,f[u2][0]);
        ans+=all;
    }
    printf("%lld\n",ans);
    return 0;
}
/*
 
3
20 3
20 3
30 1
 
 
*/

 

bzoj 1040: [ZJOI2008]骑士

标签:print   ons   不同   位运算   mes   main   eof   scanf   ted   

原文地址:https://www.cnblogs.com/lxy8584099/p/10260614.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!