题目大意:
给你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(' '); }
//弱弱说一句,第10个点实在是毒瘤,不开开关水不过去QwQ