「CF1455G」Forbidden Value 题解 (DP,线段树合并)
题目简介
已知初始值 \(x=0\) ,给定下面 \(2\) 种命令:
set
\(y\) \(v\),令 \(x=y\),或花费 \(v\) 元钱删除该命令;if
\(y\) ...end
,如果 \(x==y\),执行if...end
中的命令,否则跳过该if...end
。
你需要使用最少的花费,使得无论运行到哪里,都有 \(x \neq s\)。
分析
其实我们可以在整个操作最外面套一个 if
\(0\) … end
操作。这样所有的命令就可以化作一颗树的结构。
考虑 \(f[i][j]\) 为以 \(i\) 为根的子树中,操作完结果 \(x=j\) 的方案的最小花费。特别的,\(f[i][s]=\infin\)
如果当前结点为1操作,那么有:
\(f[i][y]=\min f[i][z] (y\ne s\ \mbox{and}\ z\ne y)\)
\(f[i][z]=f[i][z]+v(z\ne y)\)
如果当前结点为2操作,那么先对其子树做递归一遍,在进行合并:
\(f[i][y]=f[i'][y]\)
\(f[i][z]=\min {f[i][z],f[i'][z]}\)
解释一下为什么 \(f[i][y]\neq \min\ f[i][y],f[i'][y]\)。原因是发现 \(f[i][y]\) 可行后,是必须行走 \(f[i'][y]\)。而其他都是可选择的。
但是这样的数组显然是开不下的,考虑使用线段树合并来维护信息。
\(AC\ Code\)
#include<cstdio>
#include<iostream>
#include<vector>
using namespace std;
using ll=long long;
const int Maxn=2e5+5;
const ll Inf=1e18;
int lson[Maxn<<4];
int rson[Maxn<<4];
ll val[Maxn<<4];
ll laz[Maxn<<4];
int tot;
inline int &ls(int x){return lson[x];}
inline int &rs(int x){return rson[x];}
inline void add(int x,ll v){val[x]+=v;laz[x]+=v;}
inline void pushup(int x){
val[x]=min(val[ls(x)],val[rs(x)]);
}
inline void pushdown(int x){
if(!laz[x])return ;
if(ls(x))add(ls(x),laz[x]);
if(rs(x))add(rs(x),laz[x]);
laz[x]=0;
}
void modify(int &x,int l,int r,int p,ll v){
if(!x)val[x=++tot]=Inf;
if(l==r){val[x]=v;return ;}
pushdown(x);
int mid=l+r>>1;
if(p<=mid)modify(ls(x),l,mid,p,v);
else modify(rs(x),mid+1,r,p,v);
pushup(x);
}
ll query(int x,int l,int r,int p){
if(!x)return Inf;
if(l==r){return val[x];}
pushdown(x);
int mid=l+r>>1;
if(p<=mid)return query(ls(x),l,mid,p);
else return query(rs(x),mid+1,r,p);
}
void merge(int &x,int y,int l,int r){
if(!x||!y){x+=y;return ;}
if(l==r){val[x]=min(val[x],val[y]);return ;}
pushdown(x);pushdown(y);
int mid=l+r>>1;
merge(ls(x),ls(y),l,mid);
merge(rs(x),rs(y),mid+1,r);
pushup(x);
}
int op[Maxn],cnt;
int a[Maxn],b[Maxn];
int rt[Maxn];
int st[Maxn],top;
vector<int>tr[Maxn];
void dfs(int x,int k){
modify(rt[x],0,2e5,a[x],0);
for(int y:tr[x]){
if(op[y]==1){
ll tmp=val[rt[x]];
add(rt[x],b[y]);
if(a[y]!=k)
modify(rt[x],0,2e5,a[y],tmp);
}else{
ll tmp=query(rt[x],0,2e5,a[y]);
if(tmp!=Inf){
dfs(y,k);
add(rt[y],tmp);
modify(rt[x],0,2e5,a[y],Inf);
merge(rt[x],rt[y],0,2e5);
}
}
}
}
int main(){
int n,m;cin>>n>>m;
st[++top]=++cnt;
for(int i=1;i<=n;++i){
char s[5];cin>>s;
if(s[0]=='s'){
op[++cnt]=1;
cin>>a[cnt]>>b[cnt];
tr[st[top]].emplace_back(cnt);
}else if(s[0]=='i'){
op[++cnt]=2;
cin>>a[cnt];
tr[st[top]].emplace_back(cnt);
st[++top]=cnt;
}else --top;
}
val[0]=Inf;dfs(1,m);
cout<<val[rt[1]]<<'\n';
return 0;
}