P2607 [ZJOI2008]骑士

题目大意:

  给你n个点n条边,每个点只有一个出度和一个权值,请你选出若干个点,使得这些点之间两两没有边相连且权值之和最大.

解题思路:

  根据题意,不难看出n个点构成一个基环树森林且只有一个环,于是我们只需要找环断边树形dp即可.


code:

 

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
%:pragma GCC optimize("Ofast")
%:pragma GCC optimize("inline")
%:pragma GCC optimize("-fgcse")
%:pragma GCC optimize("-fgcse-lm")
%:pragma GCC optimize("-fipa-sra")
%:pragma GCC optimize("-ftree-pre")
%:pragma GCC optimize("-ftree-vrp")
%:pragma GCC optimize("-fpeephole2")
%:pragma GCC optimize("-ffast-math")
%:pragma GCC optimize("-fsched-spec")
%:pragma GCC optimize("unroll-loops")
%:pragma GCC optimize("-falign-jumps")
%:pragma GCC optimize("-falign-loops")
%:pragma GCC optimize("-falign-labels")
%:pragma GCC optimize("-fdevirtualize")
%:pragma GCC optimize("-fcaller-saves")
%:pragma GCC optimize("-fcrossjumping")
%:pragma GCC optimize("-fthread-jumps")
%:pragma GCC optimize("-funroll-loops")
%:pragma GCC optimize("-fwhole-program")
%:pragma GCC optimize("-freorder-blocks")
%:pragma GCC optimize("-fschedule-insns")
%:pragma GCC optimize("inline-functions")
%:pragma GCC optimize("-ftree-tail-merge")
%:pragma GCC optimize("-fschedule-insns2")
%:pragma GCC optimize("-fstrict-aliasing")
%:pragma GCC optimize("-fstrict-overflow")
%:pragma GCC optimize("-falign-functions")
%:pragma GCC optimize("-fcse-skip-blocks")
%:pragma GCC optimize("-fcse-follow-jumps")
%:pragma GCC optimize("-fsched-interblock")
%:pragma GCC optimize("-fpartial-inlining")
%:pragma GCC optimize("no-stack-protector")
%:pragma GCC optimize("-freorder-functions")
%:pragma GCC optimize("-findirect-inlining")
%:pragma GCC optimize("-fhoist-adjacent-loads")
%:pragma GCC optimize("-frerun-cse-after-loop")
%:pragma GCC optimize("inline-small-functions")
%:pragma GCC optimize("-finline-small-functions")
%:pragma GCC optimize("-ftree-switch-conversion")
%:pragma GCC optimize("-foptimize-sibling-calls")
%:pragma GCC optimize("-fexpensive-optimizations")
%:pragma GCC optimize("-funsafe-loop-optimizations")
%:pragma GCC optimize("inline-functions-called-once")
%:pragma GCC optimize("-fdelete-null-pointer-checks")
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define R register
#define next exnt
#define debug puts("mlg")
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
inline ll read();
inline void write(ll x);
inline void writesp(ll x);
inline void writeln(ll x);
ll tot=1,to[2000200],head[2000200],next[2000200];
inline void add(ll x,ll y){
    to[++tot]=y;next[tot]=head[x];head[x]=tot;
}
ll fight[2000200],n;
bool vis[2000200],flag;
ll l,r;
ll mem[2000200];
inline void dfs(ll x,ll fa){
    vis[x]=true;
    mem[++mem[0]]=x;
    for(R ll i=head[x],ver;i;i=next[i]){
        ver=to[i];
        if(ver==fa) continue;
        if(!vis[ver]) dfs(ver,x);
        else if(vis[ver]&&!flag){
            flag=true;
            l=x;r=ver;
        }
    }
}
ll f[2200200][3];
inline void dp(ll x,ll fa){
    f[x][0]=0;f[x][1]=fight[x];
    for(R ll i=head[x],ver;i;i=next[i]){
        ver=to[i];
        if(ver&&ver!=fa){
            dp(ver,x);
            f[x][1]+=f[ver][0];
            f[x][0]+=max(f[ver][1],f[ver][0]);
        }
    }
}
inline void clear(){
    mem[0]=0;flag=false;
}
ll ans;
inline void work(){
    if(!flag){
        ll root=mem[1];
        dp(root,-1);
        ans+=max(f[root][0],f[root][1]);
    }
    else{
        ll mx=-100;
        for(R ll i=head[l];i;i=next[i]){
            if(to[i]==r){
                to[i]=0;
                to[i^1]=0;
                break;
            }
        }
    
        dp(l,0);mx=max(mx,f[l][0]);
        dp(r,0);mx=max(mx,f[r][0]);
        ans+=mx;
    }
}
int main(){
    n=read();
    for(R ll i=1,x;i<=n;i++){
        fight[i]=read();x=read();
        add(i,x);add(x,i);
    }
    for(R ll i=1;i<=n;i++){
        if(!vis[i]){
            clear();
            dfs(i,0);
            work();        
        }
    }
    writeln(ans);
}
inline ll read(){
    ll x=0,t=1;char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') t=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*t;
}
inline void write(ll x){
    if(x<0){putchar('-');x=-x;}
    if(x<=9){putchar(x+'0');return;}
    write(x/10);putchar(x%10+'0');
}
inline void writesp(ll x){
    write(x);putchar(' ');
}
inline void writeln(ll x){
    write(x);putchar('\n');
}

 

 

 

  //弱弱说一句,第10个点实在是毒瘤,不开开关水不过去QwQ

  

posted @ 2020-07-15 16:24  月落乌啼算钱  阅读(126)  评论(0编辑  收藏  举报