XVIII.[HAOI2010]软件安装
不知道大家有没有做过这道题[CTSC1997]选课啊,反正我一看到这道题,就想起了它——都是树上背包。所以我便高高兴兴的敲了一发背包交上去。
然后呢?光荣的WA掉了。
为什么呢?
因为这道题和选课不一样;选课是你没有修完前一节课就不能修这节;但是本题是你装软件是可以随便装,想咋装就咋装的——只不过会不会起效就不知道了。因此,如果成环的话,只要整个环全装上就行了。
那么我们就SCC缩个点,在缩出来的树上背包一下就行了(实际上数据还可以加强成DAG的……)
代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,w[110],v[110],f[110][510],g[510],res,col[110],val[110],sz[110],in[110],c;
namespace SCC{
int tot,dfn[310],low[310],head[310],cnt;
struct node{
int to,next;
}edge[200100];
void ae(int u,int v){
// cout<<u<<" "<<v<<endl;
edge[cnt].next=head[u],edge[cnt].to=v,head[u]=cnt++;
}
stack<int>stk;
void Tarjan(int x){
dfn[x]=low[x]=++tot,stk.push(x);
for(int i=head[x];i!=-1;i=edge[i].next){
if(!dfn[edge[i].to])Tarjan(edge[i].to),low[x]=min(low[x],low[edge[i].to]);
if(!col[edge[i].to])low[x]=min(low[x],dfn[edge[i].to]);
}
if(low[x]<dfn[x])return;
c++;
while(stk.top()!=x)col[stk.top()]=c,val[c]+=v[stk.top()],sz[c]+=w[stk.top()],stk.pop();
col[stk.top()]=c,val[c]+=v[stk.top()],sz[c]+=w[stk.top()],stk.pop();
}
}
namespace DP{
int head[110],cnt;
struct node{
int to,next;
}edge[110];
void ae(int u,int v){
// printf("%d %d\n",u,v);
edge[cnt].next=head[u],edge[cnt].to=v,head[u]=cnt++;
}
void dfs(int x){
if(sz[x]<=m)f[x][sz[x]]=val[x];
for(int i=head[x];i!=-1;i=edge[i].next){
dfs(edge[i].to);
for(int j=0;j<=m;j++)g[j]=f[x][j];
for(int j=0;j<=m;j++)for(int k=0;j+k<=m;k++)if(f[x][j]!=-1&&f[edge[i].to][k]!=-1)g[j+k]=max(g[j+k],f[x][j]+f[edge[i].to][k]);
for(int j=0;j<=m;j++)f[x][j]=g[j];
}
}
}
int main(){
scanf("%d%d",&n,&m),memset(f,-1,sizeof(f)),memset(SCC::head,-1,sizeof(SCC::head)),memset(DP::head,-1,sizeof(DP::head));
for(int i=1;i<=n;i++)scanf("%d",&w[i]);
for(int i=1;i<=n;i++)scanf("%d",&v[i]);
for(int i=1,x;i<=n;i++){
scanf("%d",&x);
if(x)SCC::ae(x,i);
}
for(int i=1;i<=n;i++)if(!SCC::dfn[i])SCC::Tarjan(i);
// for(int i=1;i<=c;i++)printf("%d %d\n",val[i],sz[i]);
for(int i=1;i<=n;i++)for(int j=SCC::head[i];j!=-1;j=SCC::edge[j].next)if(col[i]!=col[SCC::edge[j].to])DP::ae(col[i],col[SCC::edge[j].to]),in[col[SCC::edge[j].to]]++;
for(int i=1;i<=c;i++)if(!in[i])DP::ae(0,i);
DP::dfs(0);
for(int i=0;i<=m;i++)res=max(res,f[0][i]);
printf("%d\n",res);
return 0;
}