# [BZOJ1487] no return Island (HNOI2009) - square tree + DP

Posted by Seaholme on Thu, 19 Mar 2020 18:55:51 +0100

Method: this problem needs to use square tree + DP.
Obviously, the picture given in the title is a cactus, so what this title requires is the maximum point weight and independent set on cactus.
So we turn the cactus problem into a square tree problem. DP on the dot is easy to handle, just like the tree DP, mainly the DP on the square point. Because the ring on which the square point is located and the dot on it have two adjacent points, we need to make a special judgment, that is to say, dp(i,0/1)dp(i,0/1) represents the maximum point weight sum selected or not for point ii, while for a ring, we need to make dp(i,0/1)dp(i,0/1) indicates the maximum weight sum of the selected or unselected points adjacent to the above dots. For convenience, we make dp(i,0)dp(i,0) the maximum point weight sum of unselected points, dp(i,1)dp(i,1) the maximum point weight sum of unselected points. This is a good way to do DP. The time complexity is O(n)O(n), which can be used.
Here is my code:

```#include <bits/stdc++.h>
using namespace std;
const int N=100010;
const int M=N<<2;
typedef long long ll;
int n,m,first[N]={0},firsted[N<<1]={0},tot=0,totpbc;
int low[N],dfn[N],tim=0,st[N],top=0;
int fa[N],fae[N],cir[N];
ll val[N],dp[N<<1][2]={0},cirdp[N][2];
bool vis[N],inst[N];
struct edge
{
int v,next,id;
}e[M],ed[M];

void insert(int a,int b,int id)
{
e[++tot].v=b;
e[tot].next=first[a];
e[tot].id=id;
first[a]=tot;
}

void inserted(int a,int b)
{
ed[++tot].v=b;
ed[tot].next=firsted[a];
firsted[a]=tot;
}

void combine(int x,int y)
{
int now=y;
cir[0]=0;
while(now!=x)
{
cir[++cir[0]]=now;
now=fa[now];
}
cir[++cir[0]]=x;

cirdp[0][0]=cirdp[0][1]=0;
for(int i=1;i<cir[0];i++)
{
cirdp[i][0]=cirdp[i-1][1]+dp[cir[i]][0];
cirdp[i][1]=cirdp[i-1][0]+dp[cir[i]][1];
cirdp[i][1]=max(cirdp[i][0],cirdp[i][1]);
}
dp[++totpbc][1]=cirdp[cir[0]-1][1];

cirdp[1][0]=cirdp[1][1]=0;
for(int i=2;i<cir[0]-1;i++)
{
cirdp[i][0]=cirdp[i-1][1]+dp[cir[i]][0];
cirdp[i][1]=cirdp[i-1][0]+dp[cir[i]][1];
cirdp[i][1]=max(cirdp[i][0],cirdp[i][1]);
}
if (cir[0]==2) dp[totpbc][0]=dp[1][0];
else dp[totpbc][0]=cirdp[cir[0]-2][1]+dp[cir[1]][0]+dp[cir[cir[0]-1]][0];
dp[totpbc][1]=max(dp[totpbc][1],dp[totpbc][0]);

inserted(x,totpbc);
for(int i=1;i<cir[0];i++)
inserted(totpbc,cir[i]);
}

void tarjan(int v,int laste)
{
vis[v]=inst[v]=1;
low[v]=dfn[v]=++tim;
st[++top]=v;
int now=top;
for(int i=first[v];i;i=e[i].next)
if (e[i].id!=laste)
{
if (!vis[e[i].v])
{
fa[e[i].v]=v;
fae[e[i].v]=e[i].id;
tarjan(e[i].v,e[i].id);
if (low[e[i].v]>dfn[v])
{
top--;
inst[e[i].v]=0;
inserted(v,e[i].v);
}
if (low[e[i].v]==dfn[v])
{
for(int i=top;i>now;i--)
inst[st[i]]=0;
top=now;
}
low[v]=min(low[v],low[e[i].v]);
}
else if (inst[e[i].v]) low[v]=min(low[v],dfn[e[i].v]);
}
for(int i=first[v];i;i=e[i].next)
if (fae[e[i].v]!=e[i].id&&dfn[v]<dfn[e[i].v]) combine(v,e[i].v);
for(int i=firsted[v];i;i=ed[i].next)
{
dp[v][0]+=dp[ed[i].v][1];
dp[v][1]+=dp[ed[i].v][0];
}
dp[v][1]+=val[v];
dp[v][1]=max(dp[v][1],dp[v][0]);
}

int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int a,b;
scanf("%d%d",&a,&b);
insert(a,b,i),insert(b,a,i);
}
for(int i=1;i<=n;i++)
scanf("%lld",&val[i]);

totpbc=n;
tot=0;
fa[1]=0;
tarjan(1,0);
printf("%lld",dp[1][1]);

return 0;
}```