P5391

题意:

给定一个序列和大小为 \(V\) 的背包,和 \(q\) 次操作,操作有两种。

  1. 增加一种体积为 \(x\),价值为 \(y\) 的物品在序列末尾。
  2. 删除序列末尾的物品。

每种物品有无限多个,求每次操作后背包所能装下的最大价值。

题解:

设题目中给出 \(n\) 种物品。

题目可以看成是按照时间顺序给出了一棵树,树上的每个点具有相应的价值和体积,每次操作相当于把某个节点到根的路径上所有节点取出然后跑树上背包。

此时的最坏情况就是树为一条链,此时的时间复杂度是 \(O(qn)\),空间复杂度为 \(O(Vn)\)

空间复杂度明显超限,所以要对其进行优化。

因为路径只是从根节点到某个节点,所以可以采用轻重链剖分的方式优化复杂度。对于每一条重链开一个数组,因为每个节点到根节点最多有 \(logn\) 条重链,所以空间复杂度就是 \(O(Vlogn)\),可以通过此题。

每次操作时处理当前重链上的背包,并与上一次的背包合并。

具体细节看代码。

代码:

#include <bits/stdc++.h>
using namespace std;
const int N=2e5,INF=2e9;string sg;stack <int> s;
int n,m,q,vis[N],fir[N],dfn[N],cnt,tot,fa[N],si[N],d[N],h[N],t[N],id[N],di[N],a[N],b[N],ans[N],dp[20][N];
struct edge{int v,nt;}e[N<<1];struct cb{int u,v;}c[N<<1];
void into(int u,int v){e[++cnt].v=v;e[cnt].nt=fir[u];fir[u]=cnt;}
void dfs1(int u,int f){
    si[u]=vis[u]=1;fa[u]=f;
    for(int i=fir[u];i;i=e[i].nt)
	if(e[i].v!=f){
            dfs1(e[i].v,u);si[u]+=si[e[i].v];
	    if(si[e[i].v]>si[h[u]])h[u]=e[i].v;
	}
}void dfs2(int d,int l,int x){
    for(int i=0;i<=m;i++){
	dp[d][i]=dp[l][i];
	if(i>=c[x].u)dp[d][i]=max(dp[d][i],dp[d][i-c[x].u]+c[x].v);
	ans[x]=max(ans[x],dp[d][i]);
    }for(int i=fir[x];i;i=e[i].nt)if(e[i].v!=fa[x]&&e[i].v!=h[x])dfs2(d+1,d,e[i].v);if(!h[x])return ;dfs2(d,d,h[x]);
}int main(){
    cin>>q>>m;
    for(int i=1;i<=q;i++){
	cin>>sg;if(sg[0]=='a'){n++;cin>>c[n].u>>c[n].v;if(!s.empty())into(s.top(),n);s.push(n);}
	else	s.pop();if(!s.empty())	dfn[i]=s.top();
    }for(int i=1;i<=n;i++)if(!vis[i])	dfs1(i,0),dfs2(1,0,i);
    for(int i=1;i<=q;i++)cout<<ans[dfn[i]]<<endl;return 0;
}
posted @ 2022-02-24 18:27  AIskeleton  阅读(12)  评论(0编辑  收藏  举报