题解:CF2176E Remove at the lowest cost

· · 题解

考虑无修改

先用单调栈预处理出 L_i 表示左边第一个满足 a_{L_i}>a_iR_i 同理。

对于确定的序列,贪心过程是每次选 c_i 最小的,然后把 L_iR_i 所有没被删除的元素对 i 做保留 i 的删除操作。

考虑刻画这个过程,可以理解为先按 c_i 为关键字由小到大排序,然后依次对 L_iR_i 没有被染色过的格子染上 c_i 的颜色。

我们设最后第 i 个格子颜色是 d_ia_i 最大的元素中 c_i 的最小值为 last,答案就是 (\sum_{i=1}^{n} d_i)-last(减去 last 的原因是最后只剩一个元素时多算了一次删除价值为 last 的代价)。

## 考虑有修改 修改是将一个点的 $c_i=0$,显然可以先用 $0$ 的代价将 $L_i$ 到 $R_i$ 的所有元素删除,这就相当与是把 $L_i$ 到 $R_i$ 区间颜色改为 $0$,可以用线段树区间赋 $0$,最后的答案是 $\max((\sum_{i=1}^{n} d_i)-last,0)$(和 $0$ 取最大值是当 $a_i$ 最大的元素中 $c_i$ 的最小值为 $0$ 时总代价为 $0$ 此时不需要减 $last$)。 ## 代码 ```cpp #include<bits/stdc++.h> #define int long long using namespace std; const int maxn=200005; int T,n; struct DHC{ int a,c,id; bool operator < (const DHC b) const {return c<b.c;} }arr[maxn]; namespace dhcio{ inline int read(){ char ch=getchar();int ret=0,f=1; while(ch<'0'||ch>'9'){if(ch=='-') f=-f;ch=getchar();} while(ch>='0'&&ch<='9') ret=(ret<<3)+(ret<<1)+(ch&15),ch=getchar(); return ret*f; } inline void write(int x){ if(x<0) x=-x,putchar('-'); if(x>9) write(x/10); putchar('0'+x%10); } } using namespace dhcio; struct SegmentTree{ #define ls (p<<1) #define rs (p<<1|1) int sum[4*maxn],tag[4*maxn]; void add_tag(int p,int pl,int pr,int d){sum[p]=(pr-pl+1)*d,tag[p]=d;} void push_down(int p,int pl,int pr){ if(tag[p]==-1) return; int mid=pl+pr>>1; add_tag(ls,pl,mid,tag[p]);add_tag(rs,mid+1,pr,tag[p]); tag[p]=-1; } void push_up(int p){sum[p]=sum[ls]+sum[rs];} void build(int p,int pl,int pr){ if(pl==pr){sum[p]=0;tag[p]=0;return;} int mid=pl+pr>>1; build(ls,pl,mid);build(rs,mid+1,pr); tag[p]=-1;push_up(p); } void update(int p,int pl,int pr,int L,int R,int d){ if(L<=pl&&pr<=R){add_tag(p,pl,pr,d);return;} int mid=pl+pr>>1;push_down(p,pl,pr); if(L<=mid) update(ls,pl,mid,L,R,d); if(R> mid) update(rs,mid+1,pr,L,R,d); push_up(p); } int query(int p,int pl,int pr,int L,int R){ if(L<=pl&&pr<=R) return sum[p]; int mid=pl+pr>>1,res=0;push_down(p,pl,pr); if(L<=mid) res+=query(ls,pl,mid,L,R); if(R> mid) res+=query(rs,mid+1,pr,L,R); push_up(p); return res; } #undef ls #undef rs }tree; int L[maxn],R[maxn]; void solve(){ n=read(); for(int i=1;i<=n;i++) arr[i].id=i; for(int i=1;i<=n;i++) arr[i].a=read(); for(int i=1;i<=n;i++) arr[i].c=read(); stack<int> st; for(int i=1;i<=n;i++){ while(!st.empty()&&arr[st.top()].a<=arr[i].a) st.pop(); if(st.empty()) L[i]=1;else L[i]=st.top()+1; st.push(i); } while(!st.empty()) st.pop(); for(int i=n;i;i--){ while(!st.empty()&&arr[st.top()].a<=arr[i].a) st.pop(); if(st.empty()) R[i]=n;else R[i]=st.top()-1; st.push(i); } tree.build(1,1,n);int now=0; sort(arr+1,arr+1+n);reverse(arr+1,arr+1+n); for(int i=1;i<=n;i++){ tree.update(1,1,n,L[arr[i].id],R[arr[i].id],arr[i].c); if(L[arr[i].id]==1&&R[arr[i].id]==n) now=arr[i].c; } for(int t=1;t<=n;t++){write(max(tree.sum[1]-now,0ll));putchar(' ');int pos=read();tree.update(1,1,n,L[pos],R[pos],0);} write(max(tree.sum[1]-now,0ll));putchar('\n'); } signed main(){ T=read(); while(T--) solve(); return 0; } ```