题解:CF2026F Bermart Ice Cream
题意
初始时,有一个商店,编号为 ,其中没有物品。接下来有 次操作,操作有 种:
- :新建一个商店,编号为目前的商店数 ,且该商店内的物品种类与当前商店 中的相同。
- :在商店 中新建一种物品,体积为 ,价值为 。
- :把商店 中最早出现的一种物品删除,保证删除前 内至少有一种物品。
- :对商店 中的物品做 背包,求在总体积不超过 时的最大总价值。
所有操作均合法,,对于每个操作 输出答案。
分析
由于 很大,所以不能出现背包合并,这启发我们只用加入单个物品的做法更新背包。
不妨先考虑物品构成的形态,不考虑删除,显然新加入物品时商店会继承前面的物品,这样物品之间的关系就构成了一棵树,同时,一个商店是一条从根到某个节点的链。若有删除,则相当于把链顶向下扩展,任意时刻的商店都是一条祖先-后代链,而查询就是查询这样一条链。
先不考虑细节(,我们考虑大概怎么做,可以先建出这棵树,然后离线出所有的询问,现在问题形如树上每个点都是一个物品,查询了若干条祖先-后代链的 背包的点值(本来是前缀 ,但显然可以每次转移后取前缀 使其变成点值)。考虑枚举一个分支中心 ,把跨过这个中心的链全部处理掉,具体的,找出这些链中深度最浅的链顶 ,先求出从 到 的路径上的所有点的链的背包数组,接下来从 往下延伸到所有经过 的链的链底,每次都从祖先继承下来,在链底处背包合并求点值,在合理枚举分支中心的情况下,感觉每次移动都会对应一次原来的操作,所以是 的,可以接受。
那么如何枚举才最优呢,我们考虑在 dfs 到点 时,先递归处理子树,然后判断是否有未被处理的链的链顶为 ,若有就以 为中心做一次,显然这样是最优的,因为到父亲就处理不到这条链了。简单证明一下复杂度,假设有个商店的某两个询问不相交,分别为 ,,那么处理 时就处理不到 ,但注意到这么下来链 的点被插入、删除各一次,所以完全可以把 当成一个独立开创的商店,因此每次背包都可以对应到一次操作,总复杂度为 。
做完了?不,才刚刚开始。看起来没什么思维含量的一个题,为什么算上 unofficial 只有 个 AK ?因为这是一道【】的细节码农题。
可能遇到的问题有:商店中途没有物品时,链怎么处理?复制节点 怎么处理?
这里提供我的写法:我们把整个做法大致分为三个步骤:
- 建出物品树。
- 处理出询问。
- 背包求答案。
我们希望无论何时商店链都存在,所以不妨让商店链为上开下闭,即链顶的物品不会记入答案。同时给商店 强行塞一个物品(节点 ) ,使商店 的链为 ,插入物品时动态维护商店链;另外再建一个空根 ,方便复制节点 。查询时也是类似的做即可。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
long long read(){
long long x=0,f=1;char ch=getchar();
while(!isdigit(ch))
{if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
void write(long long x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
const int N=3e4+10,M=2010;
int T,q,tot,tx,ta,P=2000,lq;
vector<int>g[N];
int f[N][16],dep[N];
int p[N],t[N];
struct clain{
int st,ed,aks;
}a[N];
int e[N],s1[N];
int id[N],ans[N],vis[N],sum[N];
void add(int fa,int x){
g[fa].push_back(x);
dep[x]=dep[fa]+1;
f[x][0]=fa;
for(int i=1;i<16;i++)f[x][i]=f[f[x][i-1]][i-1];
}
int find(int x,int fa){
for(int i=15;i>=0;i--){
if(dep[f[x][i]]>dep[fa])x=f[x][i];
}
return x;
}
vector<int>es[N],es2[N],ts[N];
int Dp[N][M];
void dfs2(int x,int fx,int *dp){
int dp2[M];
memcpy(dp2,dp,sizeof(dp2));
if(x!=fx){
for(int j=P-p[x];j>=0;j--){
dp[j+p[x]]=max(dp[j+p[x]],dp2[j]+t[x]);
}
for(int j=1;j<=P;j++)dp[j]=max(dp[j],dp[j-1]);
}
for(auto y:es2[x]){
ans[y]=0;vis[y]=1;
for(int j=0;j<=a[y].aks;j++){
ans[y]=max(ans[y],dp[j]+Dp[dep[a[y].st]][a[y].aks-j]);
}
}
sum[x]=0;
for(auto y:g[x]){
if(sum[y]){
memcpy(dp2,dp,sizeof(dp2));
dfs2(y,fx,dp2);
}
}
}
void dfs1(int x){
int son=x;
for(auto y:g[x]){
dfs1(y);
if(es[id[y]].size()>es[id[son]].size())son=y;
sum[x]+=sum[y];
}
if(id[x]!=id[son])
while(es[id[x]].size()){
es[id[son]].push_back(es[id[x]].back());
es[id[x]].pop_back();
}
id[x]=id[son];
for(auto y:g[x]){
if(y==son)continue;
while(es[id[y]].size()){
es[id[son]].push_back(es[id[y]].back());
es[id[y]].pop_back();
}
}
while(ts[x].size()&&vis[ts[x].back()]){
ts[x].pop_back();
}
if(ts[x].size()){
int md=dep[x];
for(auto y:es[id[x]]){
md=min(md,dep[a[y].st]);
}
memset(Dp[dep[x]],0,sizeof(Dp[dep[x]]));
memset(Dp[dep[x]+1],0,sizeof(Dp[dep[x]+1]));
for(int y=x;dep[y]>md;){
int fa=f[y][0];
memcpy(Dp[dep[fa]],Dp[dep[y]],sizeof(Dp[dep[fa]]));
for(int j=P-p[y];j>=0;j--){
Dp[dep[fa]][j+p[y]]=max(Dp[dep[fa]][j+p[y]],Dp[dep[y]][j]+t[y]);
}
for(int j=1;j<=P;j++)Dp[dep[fa]][j]=max(Dp[dep[fa]][j],Dp[dep[fa]][j-1]);
y=fa;
}
memcpy(Dp[0],Dp[N-5],sizeof(Dp[0]));
dfs2(x,x,Dp[0]);
es[id[x]].clear();
}
}
int main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
q=read();
tot=1;tx=1;
s1[1]=e[1]=1;dep[1]=1;
add(0,1);
lq=0;
while(q--){
int op=read(),x,y,z;
x=read();
if(op==1){
tot++;
e[++tx]=e[x];s1[tx]=s1[x];
p[tot]=p[e[tx]];
t[tot]=t[e[tx]];
add(f[e[tx]][0],tot);
if(s1[x]==e[x])s1[tx]=tot;
e[tx]=tot;
}
else if(op==2){
y=read();z=read();
tot++;
add(e[x],tot);
e[x]=tot;p[tot]=y;t[tot]=z;
}
else if(op==3){
y=find(e[x],s1[x]);
s1[x]=y;
}
else{
y=read();
a[++ta]=(clain){s1[x],e[x],y};
es[e[x]].push_back(ta);
es2[e[x]].push_back(ta);
ts[s1[x]].push_back(ta);
sum[e[x]]++;
}
}
for(int i=1;i<=tot;i++)id[i]=i;
for(auto y:g[0])dfs1(y);
for(int i=1;i<=ta;i++)printf("%d\n",ans[i]);
return 0;
}
本文作者:luckydrawbox
本文链接:https://www.cnblogs.com/luckydrawbox/p/18526414
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步