【bzoj1040】 ZJOI2008—骑士

http://www.lydsy.com/JudgeOnline/problem.php?id=1040 (题目链接)

题意

  一个基环森林,从中选出不相邻的若干个点使得这些点的点权和最大。

Solution

  把树做完以后枚举环上一点选和不选,两者取个最值就可以了。多个连通块的情况用并查集搞一下。

细节

  开LL

代码

// bzoj1040
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define LL long long
#define inf (1ll<<30)
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
using namespace std;

const int maxn=1000010;
LL f[maxn][2],t[maxn][2],ans;
int head[maxn],dag[maxn],vis[maxn],fa[maxn],p[maxn],a[maxn],w[maxn],cnt,n,m;
struct edge {int to,next;}e[maxn<<1];

void link(int u,int v) {
	e[++cnt]=(edge){v,head[u]};head[u]=cnt;
	e[++cnt]=(edge){u,head[v]};head[v]=cnt;
}
void topsort() {
	queue<int> q;
	for (int i=1;i<=n;i++) if (dag[i]==1) q.push(i);
	while (!q.empty()) {
		int x=q.front();q.pop();dag[x]--;
		for (int i=head[x];i;i=e[i].next)
			if (dag[e[i].to]>1) if (--dag[e[i].to]==1) q.push(e[i].to);
	}
}
void dfs(int x,int fa) {
	f[x][1]=w[x],f[x][0]=0;
	for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa && !dag[e[i].to]) {
			dfs(e[i].to,x);
			f[x][1]+=f[e[i].to][0];
			f[x][0]+=max(f[e[i].to][1],f[e[i].to][0]);
		}
}
void find(int x,int fa) {
	a[++m]=x;vis[x]=1;
	for (int i=head[x];i;i=e[i].next)
		if (!vis[e[i].to] && dag[e[i].to]) find(e[i].to,x);
}
int find(int x) {
	return x==fa[x] ? x : fa[x]=find(fa[x]);
}
LL dp(int x) {
	LL res=0;
	m=0;find(x,0);
	t[1][1]=f[a[1]][1];t[1][0]=0;
	t[2][1]=0;t[2][0]=f[a[1]][1]+f[a[2]][0];
	for (int i=3;i<m;i++) {
		t[i][0]=max(t[i-1][1],t[i-1][0])+f[a[i]][0];
		t[i][1]=t[i-1][0]+f[a[i]][1];
	}
	res=max(res,max(t[m-1][1],t[m-1][0])+f[a[m]][0]);
	t[1][1]=0;t[1][0]=f[a[1]][0];
	for (int i=2;i<=m;i++) {
		t[i][0]=max(t[i-1][1],t[i-1][0])+f[a[i]][0];
		t[i][1]=t[i-1][0]+f[a[i]][1];
	}
	return max(res,max(t[m][1],t[m][0]));
}
int main() {
	scanf("%d",&n);
	for (int i=1;i<=n;i++) fa[i]=i;
	for (int u,i=1;i<=n;i++) {
		scanf("%d%d",&w[i],&u);
		link(i,u);dag[i]++,dag[u]++;
		if (find(i)!=find(u)) fa[find(i)]=find(u);
	}
	topsort();
	for (int i=1;i<=n;i++) if (dag[i]) {
			p[find(i)]=i;
			dfs(i,0);
		}
	for (int i=1;i<=n;i++) if (p[i]) ans+=dp(p[i]);
	printf("%lld",ans);
	return 0;
}

 

posted @ 2017-03-09 14:17  MashiroSky  阅读(135)  评论(0编辑  收藏  举报