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; }