[GYM102155J]stairways

CXXIV.[GYM102155J]stairways

首先,考虑暴力 \(n^3\) DP——设 \(f_{i,j,k}\) 表示当前DP到第 \(i\) 个人,且第一条楼梯上到的最晚的人在时刻 \(j\) 到达,第二条楼梯在时刻 \(k\)

然后,观察到 \(j,k\) 中至少有一个值为前缀 \(\max\) 的时刻值。故状态可以被压缩到二维——\(f_{i,j}\) 表示第一条楼梯上的人是前缀 \(\max\),第二条楼梯在时刻 \(k\)

设前缀 \(max\)\(s\)。然后有

\[f_{i,j}=\begin{cases}f_{i-1,j}+s-a_i&(j<a_i)\\\min\limits_{j\leq a_i}f_{i-1,j}&(j=a_i)\\f_{i-1,j}+j-a_i&(j>a_i)\end{cases} \]

考虑 \(f_{i,j}\),其中肯定应该是 \(j\) 越小,值越大,即 \(f_{i,j}\) 应是单调递减的。假如在某个地方单调性被破坏,那肯定是在后方的东西更劣,可以直接舍去。

于是我们考虑全程只使用一个 \(f\) 数组,随着 \(i\) 增加改变里面的东西。设 \(f'\) 表示老的 \(f\) 数组,然后,假设我们已经保证了 \(f\) 的单调性,则转移式可以直接变为:

\[f_{j}=\begin{cases}f_{j}'+s-a_i&(j<a_i)\\f_{k}'&(j=a_i,\text{k是小于等于j的最大元素})\\f_{j}'+j-a_i&(j>a_i)\end{cases} \]

然后,\(a_i\) 可以在最后统一减去,优化得

\[f_{j}=\begin{cases}f_{j}'+s&(j<a_i)\\f_{k}'+a_i&(j=a_i,\text{k是小于等于j的最大元素})\\f_{j}'+j&(j>a_i)\end{cases} \]

于是我们现在要解决两个问题,一是区间加定值 \(s\),这个简单用个什么线段树平衡树之类轻松解决;关键是第二个问题,后缀全部增加 \(j\),同时还要维护单调性。

我们对于每个位置 \(j\),设小于它的最大元素是 \(k\),维护一个值为 \(\left\lfloor\dfrac{f_k-f_j}{j-k}\right\rfloor\)。当后缀带权加时,明显这个值会减少 \(1\)。而当这个值最终减少到 \(0\) 时,就说明单调性被破坏,可以删掉该元素了。

在前缀加 \(s\) 时,上述值并没有被改变;在修改 \(f_{a_i}\) 的值时,只有 \(a_i\) 附近的东西被改变了,暴力修改即可;在后缀带权加时,除了起始的地方,其他地方的值是全部减一的,于是仍然暴力修改起始处的值即可。

可以使用线段树,但这样就没法很方便地维护单调性;无论是分块还是平衡树维护都可以起到简单维护单调性的功效,直接上即可。

时间复杂度 \(O(n\sqrt{n})\)\(n\log n\),取决于使用哪种数据结构。这里采取平衡树。

代码:

/*
f[i]=f[j] (j is the maximal element smaller than i
f[j]=f[j]+s-i (j<i)
f[j]=f[j]+j-i (j>i)

tms=upper[(f[k]-f[j])/(j-k)] where k<j.
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,a[100100],rt,cnt;
#define lson t[x].ch[0]
#define rson t[x].ch[1]
struct Treap{
	int key,rd,ch[2],sz;
	ll f,tagf,tagt,tms,mn;
}t[100100];
void pushup(int x){
	t[x].mn=t[x].tms,t[x].sz=1;
	if(lson)t[x].mn=min(t[x].mn,t[lson].mn),t[x].sz+=t[lson].sz;
	if(rson)t[x].mn=min(t[x].mn,t[rson].mn),t[x].sz+=t[rson].sz;
}
void ADDF(int x,ll y){if(x)t[x].tagf+=y,t[x].f+=y;}
void ADDT(int x,ll y=1){if(x)t[x].tagt+=y,t[x].tms-=y,t[x].mn-=y,t[x].f+=1ll*y*t[x].key;}
void pushdown(int x){
	ADDF(lson,t[x].tagf),ADDT(lson,t[x].tagt);
	ADDF(rson,t[x].tagf),ADDT(rson,t[x].tagt);
	t[x].tagf=t[x].tagt=0;
}
int merge(int x,int y){
	if(!x||!y)return x+y;
	if(t[x].rd>t[y].rd){pushdown(x),t[x].ch[1]=merge(t[x].ch[1],y),pushup(x);return x;}
	else{pushdown(y),t[y].ch[0]=merge(x,t[y].ch[0]),pushup(y);return y;}
}
void splitbykey(int x,int k,int &u,int &v){//u:<k.
	if(!x){u=v=0;return;}
	pushdown(x);
	if(t[x].key<k)u=x,splitbykey(rson,k,rson,v);
	else v=x,splitbykey(lson,k,u,lson);
	pushup(x);
}
void splitbysize(int x,int k,int &u,int &v){
	if(!x){u=v=0;return;}
	pushdown(x);
	if(t[lson].sz>=k)v=x,splitbysize(lson,k,u,lson);
	else u=x,splitbysize(rson,k-t[lson].sz-1,rson,v);
	pushup(x);
}
int Newnode(int key,ll f){
	int x=++cnt;
	t[x].f=f,t[x].key=key,t[x].rd=rand()*rand();
	pushup(x);
	return x;
}
ll flor(ll x,ll y){//the floor-rounded of x/y.
	if(x<=0)return 0;
	return (x-1)/y+1;
}
void func(int k,int pre){
	int a,b,c,d,e;
	splitbykey(rt,k,b,c);
	ADDF(b,pre);
	splitbysize(b,t[b].sz-1,a,b);
	splitbykey(c,k+1,c,d);
	if(!c)c=Newnode(k,0),t[c].f=t[b].f+k-pre;//because f[b] has already been added by pre.
	else t[c].f+=k;
	t[c].tms=flor(t[b].f-t[c].f,t[c].key-t[b].key);
	pushup(c);
	ADDT(d);
	splitbysize(d,1,d,e);
	if(d)t[d].tms=flor(t[c].f-t[d].f,t[d].key-t[c].key),pushup(d);
	rt=merge(merge(merge(merge(a,b),c),d),e);
}
int getmn(int x){
	pushdown(x);
	if(lson&&t[lson].mn<=0)return getmn(lson);
	if(t[x].tms<=0)return t[x].key;
	return getmn(rson);
}
void reset(){
	while(rt&&t[rt].mn<=0){
		int k=getmn(rt);
		int a,b,c,d,e;
		splitbykey(rt,k,b,c);
		splitbysize(b,t[b].sz-1,a,b);
		splitbykey(c,k+1,c,d);
		splitbysize(d,1,d,e);
		if(d)t[d].tms=flor(t[b].f-t[d].f,t[d].key-t[b].key),pushup(d);
		rt=merge(merge(a,b),merge(d,e));
	}
}
ll getres(){
	int a,b;
	splitbysize(rt,t[rt].sz-1,a,b);
	ll tmp=t[b].f;
	rt=merge(a,b);
	return tmp;
}
void iterate(int x){
	if(!x)return;
	pushdown(x);
	iterate(lson);
	printf("%d:(F:%d TMS:%d MN:%d)\n",t[x].key,t[x].f,t[x].tms,t[x].mn);
	iterate(rson);
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	rt=Newnode(0,a[1]),t[rt].tms=0x3f3f3f3f;
	for(int i=2,j=a[1];i<=n;i++){
		j=max(j,a[i]);
		func(a[i],j);
//		puts("BEF:");iterate(rt);
		reset();
//		puts("AFT:");iterate(rt);puts("");
	}
	ll res=getres();
	for(int i=1;i<=n;i++)res-=a[i];
	printf("%lld\n",res);
	return 0;
}
/*
9
44 43 42 41 33 66 32 11 5
*/

posted @ 2021-03-31 14:49  Troverld  阅读(75)  评论(0编辑  收藏  举报