• BZOJ 1040 [ZJOI2008]骑士


    内向树dp~

    就是先找环,任取环上有边相连两点,u和v,以u为根,断开u和v之间的边,做两次树形dp,dp[i][0]表示i不选,dp[i][1]表示i选

    ①强制u不选,v随意

    ②u随意,v不选

    两种情况取最大值即可~

    View Code
     1 #include <iostream>
     2 #include <cstring>
     3 #include <cstdio>
     4 #include <cstdlib>
     5 #include <algorithm>
     6 
     7 #define N 2000000
     8 #define M 4000000
     9 
    10 using namespace std;
    11 
    12 int head[N],next[M],to[M],bh[N];
    13 int n,ban,rp,cnt,root;
    14 long long val[N],ans,res,dp[N][2];
    15 bool vis[N],v[N];
    16 
    17 inline void add(int u,int v)
    18 {
    19     to[cnt]=v; next[cnt]=head[u]; head[u]=cnt++;
    20 }
    21 
    22 inline void read()
    23 {
    24     memset(head,-1,sizeof head); cnt=0;
    25     scanf("%d",&n);
    26     for(int i=1,a;i<=n;i++)
    27     {
    28         scanf("%lld%d",&val[i],&a);
    29         add(i,a); add(a,i);
    30     }
    31 }
    32 
    33 inline void circle(int u,int fa)
    34 {
    35     for(int i=head[u];~i;i=next[i])
    36     {
    37         if(!bh[to[i]])
    38         {
    39             bh[to[i]]=true;
    40             circle(to[i],u);
    41         }
    42         else if(to[i]!=fa) rp=u,root=to[i],ban=i;
    43     }
    44 }
    45 
    46 inline void dfscir(int u)
    47 {
    48     dp[u][0]=0; dp[u][1]=val[u];
    49     for(int i=head[u];~i;i=next[i])
    50         if(i!=ban&&(i^1)!=ban&&!vis[to[i]])
    51         {
    52             vis[to[i]]=true;
    53             dfscir(to[i]);
    54             dp[u][1]+=dp[to[i]][0];
    55             dp[u][0]=max(dp[to[i]][0],dp[to[i]][1])+dp[u][0];
    56         }
    57 }
    58 
    59 inline void dfsban(int u)
    60 {
    61     dp[u][0]=0; dp[u][1]=val[u];
    62     for(int i=head[u];~i;i=next[i])
    63         if(i!=ban&&(i^1)!=ban&&!v[to[i]])
    64         {
    65             v[to[i]]=true;
    66             dfsban(to[i]);
    67             dp[u][1]+=dp[to[i]][0];
    68             if(to[i]==rp) dp[u][0]+=dp[to[i]][0];
    69             else dp[u][0]+=max(dp[to[i]][0],dp[to[i]][1]);
    70         }
    71 }
    72 
    73 inline void go()
    74 {
    75     for(int i=1;i<=n;i++)
    76         if(!bh[i])
    77         {
    78             root=-1;bh[i]=true;
    79             circle(i,-1);
    80             vis[root]=true; dfscir(root); res=dp[root][0];
    81             v[root]=true; dfsban(root); res=max(res,max(dp[root][0],dp[root][1]));
    82             ans+=res;
    83         }
    84     printf("%lld\n",ans);
    85 }
    86 
    87 int main()
    88 {
    89     read();
    90     go();
    91     return 0;
    92 }
  • 相关阅读:
    Linux的优缺点,Linux与windows的区别
    一文带你读懂 Mysql 和 InnoDB存储引擎
    由浅入深一个Demo带你认识Restful风格的架构
    同步锁Synchronized与Lock的区别?
    认识多线程中start和run方法的区别?
    Java多线程与并发相关问题
    初识WebSocket
    Tomcat与Nginx服务器的配合使用及各自的区别
    Java内存模型相关原则详解
    你对区块链的理解还停留在炒币上吗
  • 原文地址:https://www.cnblogs.com/proverbs/p/2867062.html
Copyright © 2020-2023  润新知