根据上帖中特殊性质的核心代码。核心思路是找出大环,预处理出每个岛上取或不取接入点的最大值,然后断环为链,DP 出分别强制不选链首、不选链尾的 max 得到答案。但如此只有 50pts。
inline void prework(int x,int fa)
{
anc[x]=fa,de[x]=de[fa]+1,a[x][1]=val[x];
if(fa == rt) mark[x]=true;//大环
for(unsigned int i=0;i<to[x].size();i++) if(to[x][i]^fa)
prework(to[x][i],x);
if(de[x] == 5 || de[x] == 3)
{//根据特殊性质只考虑左右儿子进行DP
int lc=to[x][0],rc=to[x][1];
a[fa][1]+=a[lc][0]+a[rc][0];
a[fa][0]+=max(max(a[lc][0]+a[rc][1],a[rc][0]+a[lc][1]),a[lc][0]+a[rc][0]);
}
return;
}
inline void get_link(int x)
{//找大环
if(vis[x]) return;
vis[x]=true,rnk[++rnk[0]]=x;
Edge(i,x) if(mark[e[i].t] && !vis[e[i].t])
return get_link(e[i].t);
return;
}
int main()
{
cnt=n=read(),m=read();
For(i,1,m) ff=read(),tt=read(),add(ff,tt),add(tt,ff);
For(i,1,n) val[i]=read();
build(1);
For(i,n+1,cnt) if(to[i].size() > to[rt].size()) rt=i;
prework(rt,0);
For(i,1,n) if(mark[i]) {get_link(i);break;}
For(i,1,rnk[0]-1)//强制不选链首
{
f[i][1]=f[i-1][0]+a[rnk[i]][1];
f[i][0]=max(f[i-1][0],f[i-1][1])+a[rnk[i]][0];
}
ans=max(f[rnk[0]-1][0],f[rnk[0]-1][1])+a[rnk[rnk[0]]][0];
Down(i,rnk[0],2)//强制不选链尾
{
f[i][1]=f[i+1][0]+a[rnk[i]][1];
f[i][0]=max(f[i+1][0],f[i+1][1])+a[rnk[i]][0];
}
printf("%d\n",max(ans,max(f[2][0],f[2][1])+a[rnk[1]][0]));