「CF1455G」Forbidden Value 题解 (DP,线段树合并)

题目简介

已知初始值 \(x=0\) ,给定下面 \(2\) 种命令:

  1. set \(y\) \(v\),令 \(x=y\),或花费 \(v\) 元钱删除该命令;
  2. 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;
}

$$-----EOF-----$$

posted @ 2022-10-04 19:12  AlienCollapsar  阅读(51)  评论(0编辑  收藏  举报
// 生成目录索引列表 // ref: http://www.cnblogs.com/wangqiguo/p/4355032.html // modified by: zzq