做法1:
1.通过并查集维护连通性找出所有基环树的环的起点终点
2.对于每一个起点终点dfs不选这个点(和没有上司的舞会一摸一样的dfs),取max累加答案
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
//================================
#define debug(a) cout << #a": " << a << endl;
#define rep(i, ll,rr) for(int i = ll; i <= rr; ++i)
const int N =2e6+10,INF = 1e9;
//================================
typedef pair<int,int> pii;
#define x first
#define y second
typedef long long LL; typedef unsigned long long ULL; typedef long double LD;
inline LL read() { LL s = 0, w = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') w = -1; for (; isdigit(ch); ch = getchar()) s = (s << 1) + (s << 3) + (ch ^ 48); return s * w; }
inline void print(LL x, int op = 10) { if (!x) { putchar('0'); if (op) putchar(op); return; } char F[40]; LL tmp = x > 0 ? x : -x; if (x < 0)putchar('-'); int cnt = 0; while (tmp > 0) { F[cnt++] = tmp % 10 + '0'; tmp /= 10; } while (cnt > 0)putchar(F[--cnt]); if (op) putchar(op); }
//=================================
int n,m,e[N],ne[2*N],h[N],node[N],idx=0,x,y,ans=0;
LL fa[N],f[N][2];
bool st[N],ins[N];
vector<pii> root;
/*
先使用并查集维护出所有基环树的断开的两个结点
对每一棵基环树各跑一遍两棵子树都不选
*/
void add(int a,int b){
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
int find(int x){
return x==fa[x]?fa[x]:find(fa[x]);
}
LL dfs(int u,int p){
f[u][0] = 0,f[u][1] = node[u];
for(int i=h[u];~i;i=ne[i]){
int j = e[i];
if(j==p) continue;
dfs(j,u);
f[u][0] += max(f[j][0],f[j][1]);
f[u][1] += f[j][0];
}
return f[u][0];
}
signed main(){
memset(h,-1,sizeof h);
n = read();
rep(i,1,n) fa[i] = i; //初始化并查集
rep(i,1,n){
node[i]=read(),x=read();
int pa=find(i),pb=find(x);
if(pa!=pb){
fa[pa]=pb;
add(x,i),add(i,x);
}
else
root.push_back({i,x});
}
LL sum = 0;
for(auto u:root)
sum += max(dfs(u.x,-1),dfs(u.y,-1));
printf("%lld\n",sum);
return 0;
}
做法2:
对于基环树森林
1.找出所有环
2.对于每一个环做dfs分别得到选起点和不选起点的答案取max
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
//================================
#define debug(a) cout << #a": " << a << endl;
#define rep(i, ll,rr) for(int i = ll; i <= rr; ++i)
const int N =1e6+10,INF = 1e9;
//================================
typedef pair<int,int> pii;
#define x first
#define y second
typedef long long LL; typedef unsigned long long ULL; typedef long double LD;
inline LL read() { LL s = 0, w = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') w = -1; for (; isdigit(ch); ch = getchar()) s = (s << 1) + (s << 3) + (ch ^ 48); return s * w; }
inline void print(LL x, int op = 10) { if (!x) { putchar('0'); if (op) putchar(op); return; } char F[40]; LL tmp = x > 0 ? x : -x; if (x < 0)putchar('-'); int cnt = 0; while (tmp > 0) { F[cnt++] = tmp % 10 + '0'; tmp /= 10; } while (cnt > 0)putchar(F[--cnt]); if (op) putchar(op); }
//=================================
int n,e[N],node[N],h[N],rm[N],ne[N],idx=0;
LL f1[N][2],f2[N][2],ans=0;
bool st[N],ins[N];
inline void add(int a,int b){
e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}
void dfs_f(int u,int avo,LL f[][2]){
//f[u][0] = 0;
for(int i = h[u];~i; i = ne[i]){
if(rm[i]) continue; //被斩断之边
int j = e[i];
dfs_f(j,avo,f);
f[u][0] += max(f[j][0],f[j][1]);
}
f[u][1]=-INF;
if(u!=avo){
f[u][1] = node[u];
for(int i=h[u];~i;i=ne[i]){
if(rm[i]) continue;
int j = e[i];
f[u][1] += f[j][0];
}
}
}
void dfs_s(int u){
st[u] = ins[u] = true;
for(int i=h[u];~i;i=ne[i]){
int j=e[i];
if(!st[j]) dfs_s(j);
else if(ins[j]){
rm[i] = 1;
dfs_f(j,-1,f1);
dfs_f(j,u,f2);
ans+=max(f1[j][0],f2[j][1]);
}
}
ins[u]=false;
}
signed main(){
memset(h,-1,sizeof h);
n = read();
rep(i,1,n){
int a= read(),b=read();
add(b,i);
node[i] = a;
}
rep(i,1,n)
if(!st[i])
dfs_s(i);
print(ans);
return 0;
}