题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1040
题意:基环树林最大权独立集。
找环,任意拆环,从拆掉的两个端点处强制不选做树形 dp,正确性显然。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
#include <cmath> #include <queue> #include <cstdio> #include <iomanip> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define N 1000010 #define ll long long using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } struct zgz { int next,to; }edge[N<<1]; int cnt=2,head[N]; void add(int from,int to) { edge[cnt].to=to; edge[cnt].next=head[from]; head[from]=cnt++; } inline ll Mx(ll a,ll b) {return a>b?a:b;} ll f[N],g[N],ans; int n,a[N],ban,A,B; bool v[N]; void dfs(int x,int fa) { v[x]=1; for(int i=head[x];i;i=edge[i].next) { int to=edge[i].to; if((i^1)==fa)continue ; if(v[to]) { A=x,B=to,ban=i; continue ; } dfs(to,i); } } void DP(int x,int fa) { f[x]=a[x]; g[x]=0; for(int i=head[x];i;i=edge[i].next) { int to=edge[i].to; if(i==ban||(i^1)==ban||(i^1)==fa)continue ; DP(to,i); f[x]+=g[to],g[x]+=Mx(f[to],g[to]); } } int main() { n=read(); for(int i=1;i<=n;i++) { a[i]=read(); int x=read(); add(x,i),add(i,x); } for(int i=1;i<=n;i++) if(!v[i]) { dfs(i,0); DP(A,0); ll tmp=g[A]; DP(B,0); tmp=Mx(tmp,g[B]); ans+=tmp; } printf("%lld\n",ans); } |
Comments | NOTHING