[BZOJ] 1040: [ZJOI2008]骑士
最初想成了缩点了,感觉一个强连通分量只能选出一个人,gg...
正解基环树dp,把环断开后强制两个断点分别不选进行dp即可。
今天电脑抽风,老吞代码..
#include<iostream> #include<cstring> #include<cstdio> #define int long long using namespace std; inline int rd() { int ret=0,f=1; char c; while(c=getchar(),!isdigit(c))f=c=='-'?-1:1; while(isdigit(c))ret=ret*10+c-'0',c=getchar(); return ret*f; } const int MAXN=1000050; int val[MAXN],wei[MAXN]; struct Edge { int from,next,to; Edge(int x=0,int y=0,int w=0) {from=x;next=y;to=w;} } e[MAXN<<1]; int ecnt=1,head[MAXN]; inline void add(int x,int y){ e[++ecnt]=Edge(x,head[x],y); head[x]=ecnt; } bool vis[MAXN]; int n; int f[MAXN][2]; int cx,cy,ci; void dfs(int x,int pre){ f[x][1]=val[x];f[x][0]=0; for(int i=head[x];i;i=e[i].next){ int v=e[i].to; if(v==pre||i==ci||(i==(ci^1))) continue; dfs(v,x); f[x][1]+=f[v][0]; f[x][0]+=max(f[v][0],f[v][1]); } } void findCircle(int x,int pre){ vis[x]=1; for(int i=head[x];i;i=e[i].next){ int v=e[i].to; if(v==pre) continue; if(vis[v]) {cx=x,cy=v,ci=i;continue;} findCircle(v,x); } } int ans; signed main(){ n=rd(); int x,y,w; for(int i=1;i<=n;i++){ val[i]=rd();x=rd(); add(x,i);add(i,x); } int ans1=0,ans2=0; for(int i=1;i<=n;i++){ if(vis[i]) continue; findCircle(i,0); dfs(cx,0); ans1=f[cx][0]; dfs(cy,0); ans2=f[cy][0]; ans+=max(ans1,ans2); } cout<<ans; }
本文来自博客园,作者:GhostCai,转载请注明原文链接:https://www.cnblogs.com/ghostcai/p/9400411.html