• BZOJ1040[ZJOI2008]骑士


     1 #include <cmath>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <iostream>
     5 #include <algorithm>
     6 using namespace std;
     7 
     8 typedef long long ll;
     9 const int N=1000005,M=2000005;
    10 
    11 int n,tot,U,V,E,now[N],prep[M],son[M],val[N];
    12 ll ans,f[N],g[N];
    13 bool vis[N];
    14 
    15 int read(){
    16     static int x,f; static char ch; x=0,f=1;
    17     for (ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') f=-1;
    18     for (;isdigit(ch);ch=getchar()) x=x*10+ch-'0'; return x*f;
    19 }
    20 
    21 void link(int x,int y){prep[++tot]=now[x],now[x]=tot,son[tot]=y;}
    22 
    23 void dfs(int x,int y){
    24     vis[x]=1;
    25     for (int i=now[x],so=son[i];i!=-1;i=prep[i],so=son[i]){
    26         if (so!=y){
    27             if (vis[so]){
    28                 U=x,V=so,E=i;
    29                 continue;
    30             }else dfs(so,x);
    31         }
    32     }
    33 }
    34 
    35 void tree_dp(int x,int y,int ban){
    36     f[x]=val[x],g[x]=0;
    37     for (int i=now[x],so=son[i];i!=-1;i=prep[i],so=son[i]){
    38         if (so!=y&&i!=ban&&(i^1)!=ban){
    39             tree_dp(so,x,ban);
    40             f[x]+=g[so],g[x]+=max(f[so],g[so]);
    41         }
    42     }
    43 }
    44 
    45 int main(){
    46     n=read(); tot=-1;
    47     memset(now,-1,sizeof(now));
    48     for (int x,i=1;i<=n;i++){
    49         val[i]=read(),x=read();
    50         link(x,i),link(i,x);
    51     }
    52     ans=0;
    53     for (int i=1;i<=n;i++){
    54         if (!vis[i]){
    55             dfs(i,0);
    56             tree_dp(U,0,E);
    57             ll x=g[U];
    58             tree_dp(V,0,E);
    59             ans+=max(x,g[V]);
    60         }
    61     }
    62     printf("%lld
    ",ans);    
    63     return 0;
    64 }
    View Code

    题目大意:给定一个基环外向森林,点带权,求最大点独立集。n<=10^6.

    做法:基环树dp,设(u,v)为环上的一条边,f[x]表示以x为根的子树中选x的最大权和,g[x]不选。

    考虑如下步骤:

    1:将这条边断开,变为树。

    2:u,v必有一个点不选,考虑分别以u,v为根做一次dp,然后用max(g[u],g[v])更新答案。

    细节:(u,v)怎么找? dfs一次,如果x的出边son之前访问过了,那么(x,son)就是换上的一条边,记录一下即可。

  • 相关阅读:
    mycat zookeeper 使用
    eclipse中使用springboot的技巧
    docker中zookeeper集群的安装与使用 以及zookeeper集群对mysq集群的管理
    以两台Linux主机在docker中实现mysql主主备份以用nginx实现mysql高可用
    nginx图片静态资源服务器以及添加认证
    nginx的stream模块实现mysql负载均衡
    cmd中结束一个正在运行的命名ctrl+c
    遇到错误Check the judgetypet-InlineParameterMap.
    2019年新个税计算器及源代码
    linux批量替换
  • 原文地址:https://www.cnblogs.com/OYzx/p/7081849.html
Copyright © 2020-2023  润新知