题解 CF1455G【Forbidden Value】
题意
有 $n$ 行指令,你需要依次执行这些指令。
初始时,你有一个变量 $x=0$,共有三种指令:
set y v,令 $x\gets y$,或用 $v$ 的代价删去这条指令;if y,如果 $x=y$,则执行其范围内的指令,否则跳过其范围内的指令;end,用于声明上一个还未声明范围的if指令的范围。
给一个数 $s$,求用最少的代价使得没有一个时刻 $x=s$。
$n\le 2\times 10^5$,$s,y\le 2\times 10^5$。
思路
考虑将指令看成树形结构,将每条指令看为直属的 if 指令的子节点。这样子是一个森林,在最外层补上 if 0 end 将其转成树。
考虑树形 dp,先将所有 set 撤销,代价挂在父节点上,令 $dp_{i,j}$ 表示执行 $i$ 子树内的指令,最终 $x=j$ 能撤销的最多代价。
直接做是很不优秀的,我们可以发现 $j$ 的取值只有 $i$ 子树内 $y$ 的取值范围,并且 $i$ 的取值范围是所有子节点取值范围的并,于是可以考虑启发式合并。
对每个结点开 map 和 multiset 分别存储 $dp$ 数组和快速修改计算 $dp_{i,k}$ 的最小值。注意在启发式合并将父节点合并到子节点时子节点的 $dp$ 值都未加上其兄弟结点的贡献,开个辅助数值记录全局加 tag 即可。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
namespace IO{//by cyffff
}
const int N=2e5+10;
int n,s,res,f[N],t[N],v[N],p[N];
ll d[N];//子节点撤销价格之和
vector<int>a[N];
map<int,ll>dp[N];//可以撤销的贡献
multiset<ll>mn[N];
inline void dfs(int x){
mn[x].insert(dp[x][p[x]]=0);
for(auto to:a[x]){
if(t[to]==1){
if(p[to]!=s){
if(dp[x].count(p[to])){
ll tmp=dp[x][p[to]];
dp[x][p[to]]=(*mn[x].begin())-v[to];
mn[x].erase(mn[x].find(tmp));
}else{
dp[x][p[to]]=(*mn[x].begin())-v[to];
}
mn[x].insert(dp[x][p[to]]);
}
d[x]+=v[to];
}else if(dp[x].count(p[to])){
dfs(to);
ll tmp=dp[x][p[to]]+d[to];
if(dp[to].size()<=dp[x].size()){
for(auto it:dp[to]){
int val=it.first;
ll cst=it.second;
if(!dp[x].count(val)) dp[x][val]=tmp+cst;
else{
mn[x].erase(mn[x].find(dp[x][val]));
if(val==p[to]) dp[x][val]=tmp+cst;
else dp[x][val]=min(dp[x][val],tmp+cst);
}
mn[x].insert(dp[x][val]);
}
}else{
d[x]+=tmp;//全体 +tmp 不好处理 加在 d 上
for(auto it:dp[x]){
int val=it.first;
ll cst=it.second;
if(!dp[to].count(val)) dp[to][val]=-tmp+cst;
else{
mn[to].erase(mn[to].find(dp[to][val]));
if(val!=p[to]) dp[to][val]=min(dp[to][val],-tmp+cst);
}
mn[to].insert(dp[to][val]);
}
swap(dp[x],dp[to]);
swap(mn[x],mn[to]);
}
}
}
}
int main(){
n=read(),s=read();
for(int i=1;i<=n;i++){
char opt=getc();
if(opt=='s'){
a[res].push_back(i);
t[i]=1,p[i]=read(),v[i]=read();
}else if(opt=='i'){
p[i]=read();
a[res].push_back(i);
t[i]=2,f[i]=res,res=i;
}else{
res=f[res];
getc(),getc();
}
}
dfs(0);
write(d[0]+(*mn[0].begin()));
flush();
}
再见 qwq~

浙公网安备 33010602011771号