BZOJ1040 [ZJOI2008]骑士 环套树/dp

借题区别了一下环套树和仙人掌

常见做法是拆环做2次DP

邻接表的话也能做,vis一下封堵点,第二次再vis到放行就好

//#include<bits/stdc++.h>  
#pragma comment(linker, "/STACK:1024000000,1024000000")   
#include<stdio.h>  
#include<algorithm>  
#include<queue>  
#include<string.h>  
#include<iostream>  
#include<math.h>  
#include<set>  
#include<map>  
#include<vector>  
#include<iomanip>  
using namespace std;  
#define ll long long  
#define pb push_back  
#define FOR(a) for(int i=1;i<=a;i++)  
const int inf=0x3f3f3f3f;  
 
const int maxn=1e6+5;    
 
ll a[maxn];
int n;

struct EDGE{
	int u,v,nxt;
}G[maxn<<1];
int tot,head[maxn];
void init(){tot=0;memset(head,-1,sizeof head);}
void addedge(int u,int v){
	G[tot]=(EDGE){u,v,head[u]};head[u]=tot;tot++;
	G[tot]=(EDGE){v,u,head[v]};head[v]=tot;tot++;
}
bool s[maxn<<1];

ll f[maxn][2];

bool flag;
int vis[maxn];
int l,r;

void dfs(int u,int fa){
	vis[u]=1;
	for(int i=head[u];~i && !flag;i=G[i].nxt){
		if(G[i].v!=fa){
			if(vis[G[i].v]){
				l=u,r=G[i].v;
				s[i]=s[i^1]=1;
				flag=1;
				break;
			}
			dfs(G[i].v,u);
		}
	}
}
void dp(int u,int fa,int fob){
	vis[u]=1;
	if(u!=fob)f[u][1]=a[u];
	else f[u][1]=0;
	f[u][0]=0;
	for(int i=head[u];~i;i=G[i].nxt){
		if(G[i].v!=fa && !s[i]){
			dp(G[i].v,u,fob);
			f[u][0]+=max(f[G[i].v][0],f[G[i].v][1]);
			f[u][1]+=f[G[i].v][0];
		}
	}
}

int main(){
	scanf("%d",&n);
	init();
	for(int i=1,x;i<=n;i++){
		scanf("%lld%d",&a[i],&x);
		addedge(i,x);
	}
	ll ans=0;
	for(int i=1;i<=n;i++){
		if(!vis[i]){
			flag=false;
			dfs(i,0);
			ll tmp=0;
			dp(l,0,r);

			tmp=max(f[l][0],f[l][1]);

			dp(r,0,l);
			tmp=max(tmp,max(f[r][0],f[r][1]));
				
			ans+=tmp;
		}
	}
	printf("%lld\n",ans);
}


posted @ 2017-12-01 22:05  Drenight  阅读(134)  评论(0编辑  收藏  举报