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