首页 > 其他分享 >Luogu2607 & Luogu1453 基环树dp

Luogu2607 & Luogu1453 基环树dp

时间:2022-09-28 18:01:13浏览次数:51  
标签:int fat 基环树 continue maxn Luogu2607 include dp

2607:一个基环树,有点权,全是有向边,选儿子则不能选父亲(反之亦然),问选出的集合的最大点权和
注意到题目的特殊性,如果i->hatred[i],那么就是一个内向树,否则为外向树
内向树好找环,但是不方便统计答案,于是想到可以用外向树,在环上任一点断环成链,然后做两次树形dp(因为这一条边也是要限制的,于是我们可以钦定断出来那条边的一个点一定不选,然后以另一点为根做dp,再反过来来一次,因为这两点一定不可能同时选)
所以内向外向树都需要,树形dp就是简单的没有上司的舞会

1453:同2607,改成无向边
这题要建基环树,然后基本相同,注意要判一下不能经过被断的边

2607

// by SkyRainWind
#include <cstdio>
#include <queue>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>

using namespace std;

typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f, maxn=1e6+1;

int n;
vector<int>g[maxn],ed[maxn];
int a[maxn];
LL dp[maxn][2];
int vdfs[maxn], fa[maxn];
int root, hh;

void topo(int x){
	vdfs[x] = 1;
	for(int u : ed[x]){
		if(vdfs[u]){hh = u;continue;}
		topo(u);
	}
}

void upd(int x,int fat = -1){
	vdfs[x] = 1;
	dp[x][0] =0, dp[x][1] = a[x];
	for(int u : g[x]){
		if(u == root){dp[x][1] = -inf;continue;}
		upd(u, x);
		dp[x][0] += max(dp[u][0], dp[u][1]);
		dp[x][1] += dp[u][0];
	}
}

signed main(){
//	freopen("2607.in","r",stdin);
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		int to;
		scanf("%d%d",&a[i],&to);
		g[to].push_back(i);
		ed[i].push_back(to);
		fa[i] = to; 
	}
	LL ans = 0;
	for(int i=1;i<=n;i++){
		if(vdfs[i])continue;
		int cr[2],cc=0;
		int pre = i;
		while(!vdfs[pre]){
			vdfs[pre] = 1;
//			cr.push_back(pre);
			pre = fa[pre];
		}
		hh = pre;
		do{
			cr[1] = cr[0];
			cr[0] = hh;
			hh = fa[hh];
		}while(hh != pre);
		root = cr[0];
		upd(root);
		LL t1 = max(dp[root][0], dp[root][1]);
		root = cr[1];
		
		upd(root);
		ans += max(t1, max(dp[root][0], dp[root][1]));
	}
	printf("%lld\n",ans);

	return 0;
}

1453

// by SkyRainWind
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>

using namespace std;

typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f, maxn=1e5 + 5;

int n,p[maxn];
vector<int>g[maxn];
int vis[maxn], rt, prt, dp[maxn][2];

void dfs(int x,int fat = -1){
	vis[x] = 1;
	for(int u : g[x]){
		if(u == fat)continue;
		if(vis[u]){rt = u;prt = x;continue;}
		dfs(u, x);
	}
}

void upd(int x,int fat = -1){
	dp[x][0] = 0, dp[x][1] = p[x];
	for(int u : g[x]){
		if(u == fat || (x == rt && u == prt))continue;
		if(u == rt){
			dp[x][1] = -inf;
			continue;
		}
		upd(u, x);
		dp[x][1] += dp[u][0];
		dp[x][0] += max(dp[u][0], dp[u][1]);
	}
}

signed main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",&p[i]);
	for(int i=1;i<=n;i++){
		int x,y;scanf("%d%d",&x,&y);
		++ x, ++ y;
		g[x].push_back(y), g[y].push_back(x);
	}
	double kf;scanf("%lf",&kf);
	dfs(1);
	upd(rt);
	int t1 = max(dp[rt][0], dp[rt][1]);
	swap(rt, prt);
	upd(rt);
	int ans = max(t1, max(dp[rt][0], dp[rt][1]));
	printf("%.1f\n",kf * ans);

	return 0;
}

标签:int,fat,基环树,continue,maxn,Luogu2607,include,dp
From: https://www.cnblogs.com/SkyRainWind/p/16739062.html

相关文章