BZOJ1040-[ZJOI2008]騎士
阿新 • • 發佈:2019-01-31
題解:
題意:有一個基環樹森林,每個點有權值,取出互不相鄰的任意個點,問最大權值和是多少。
先考慮是一棵樹的情況:
表示以為根的子樹中取或不取的最大權值和
那加一條邊變成了環之後呢?
取出環上相鄰的兩個點,,將連邊斷開,變成一棵樹,而這兩個點不能同時取。
分別以這兩個點為根做樹形,
。
#include<bits/stdc++.h>
#define N 2000005
#define ll long long
using namespace std;
int tot=-1,rr,rl,head[N],s[N],n,vis[N],flag;
ll f[N][2],ans,a[N];
struct node
{
int next,vet;
}edge[N];
void add(int u,int v)
{
edge[++tot].vet=v;
edge[tot].next=head[u];
head[u]=tot;
}
void dfs(int u,int fa)
{
vis[u]=true;
for(int i=head[u];i!=-1&&(!flag);i=edge[i].next)
{
int v=edge[i].vet;
if(v!=fa)
{
if(vis[v])
{
rl=u;
rr=v;
s[i]=s[i^1]=-1;
flag=true;
break ;
}
dfs(v,u);
}
}
}
void dp(int u,int fa,int ban)
{
vis[u]=true;
if(u!=ban)f[u][1]=a[u];else f[u][1]=0;
f[u][0]=0;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].vet;
if(v!=fa&&s[i]!=-1)
{
dp(v,u,ban);
f[u][0]+=max(f[v][0],f[v][1]);
f[u][1]+=f[v][0];
}
}
}
int main()
{
memset(head,-1,sizeof(head));
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int x;
scanf("%lld%d",&a[i],&x);
add(x,i);add(i,x);
}
for(int i=1;i<=n;i++)
if(!vis[i])
{
flag=false;
dfs(i,0);
ll mx=0;
dp(rl,0,rr);
mx=max(f[rl][0],f[rl][1]);
dp(rr,0,rl);
mx=max(mx,max(f[rr][0],f[rr][1]));
ans+=mx;
}
printf("%lld\n",ans);
}