求Hack
查看原帖
求Hack
557754
Kalenist楼主2023/6/14 17:23

根据上帖中特殊性质的核心代码。核心思路是找出大环,预处理出每个岛上取或不取接入点的最大值,然后断环为链,DPDP 出分别强制不选链首、不选链尾的 maxmax 得到答案。但如此只有 50pts50pts。

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]));
2023/6/14 17:23
加载中...