P1970 [NOIP 2013 提高组] 花匠

题目传送门

首先,我们注意到,每朵花的高度具体数值并不重要,重要的是花与花之间的相对高度大小,所以我们首先可以离散化,把值域变成与\(N\)一个量级。

然后我们设\(gao_i\)为如果以第\(i\)盆花作为结尾,并且\(i\)的高度高于它前面一盆花的情况下,能选上多少盆花。

同理设\(di_i\)表示如果以第\(i\)盆花作为结尾,并且\(i\)的高度低于它前面一盆花的情况下,能选上多少盆花。

那么一个很显然的转移方程就出来了:

\[ \begin{cases} gao_i=\max\limits_{j=1}^{i-1} [h_j<h_i] \times (di_j+1) \\ di_i=\max\limits_{j=1}^{i-1} [h_j>h_i] \times (gao_j+1) \\ \end{cases} \]

直接转移肯定是会TLE的,但是既然只需要找满足条件的最大值,我们使用两棵权值线段树分别维护\(gao、di\)的区间最大值。

具体说,假设某个线段树的节点维护的区间是\([l,r]\),区间最大值为\(mx\),那么它就表示高度为\([l,r]\)的所有花中,\(gao_i/di_i\)(若为维护\(di_i\)的线段树此处就为\(di_i\),否则为\(gao_i\))的最大值为\(mx\)

这样我们就能以\(O(nlogh_{max})\)的时间复杂度通过本题。理论上不离散化的话时间复杂度仍然是正确的,但是线段树常数很大,为了防止TLE呢,还是离散化吧qwq

代码:

P1970
#include<bits/stdc++.h>
#define int long long
#define ls (id<<1)
#define rs (id<<1|1)
using namespace std;

inline int read(){
	int x=0,f=1;char c=getchar();
	while(c<48){
		if(c=='-') f=-1;
		c=getchar();
	} 
	while(c>47) x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}

const int N=1e5+5;
int n,a[N],b[N],gao[N],di[N],ans;
struct sw{
	int l,r,mx;
}tr[2][4*N];

inline void build(int id,int l,int r,int op){
	tr[op][id].l=l;tr[op][id].r=r;
	if(l==r){
		tr[op][id].mx=0;
		return ;
	}
	int mid=(l+r)>>1;
	build(ls,l,mid,op);build(rs,mid+1,r,op);
	tr[op][id].mx=max(tr[op][ls].mx,tr[op][rs].mx);
}

inline void update(int id,int pos,int k,int op){
	if(tr[op][id].l==pos&&tr[op][id].r==pos){
		tr[op][id].mx=max(tr[op][id].mx,k);
		return ;
	}
	int mid=(tr[op][id].l+tr[op][id].r)>>1;
	if(pos<=mid){
		update(ls,pos,k,op);
	} 
	else{
		update(rs,pos,k,op);
	} 
	tr[op][id].mx=max(tr[op][ls].mx,tr[op][rs].mx);
}

inline int query(int id,int l,int r,int op){
	if(l<=tr[op][id].l&&tr[op][id].r<=r){
		return tr[op][id].mx;
	}
	int mid=(tr[op][id].l+tr[op][id].r)>>1;int ans=0;
	if(l<=mid) ans=max(ans,query(ls,l,r,op));
	if(r>mid) ans=max(ans,query(rs,l,r,op));
	return ans;
}

signed main(){
	n=read();
	for(int i=1;i<=n;i++){
		a[i]=read();b[i]=a[i];
	}
	build(1,1,n,0);build(1,1,n,1);
	//0表示di数组的线段树,1是gao数组的线段树 
	sort(b+1,b+n+1);
	int len=unique(b+1,b+n+1)-b-1;
	for(int i=1;i<=n;i++){
		a[i]=lower_bound(b+1,b+len+1,a[i])-b;
	}
	for(int i=1;i<=n;i++){
		gao[i]=query(1,1,a[i]-1,0)+1;
		 
		di[i]=query(1,a[i]+1,n,1)+1;
		
		update(1,a[i],gao[i],1);
		update(1,a[i],di[i],0);
		//        ^
		//        |
		//更新a[i]位置上的值 
		ans=max(ans,max(gao[i],di[i]));
	}
	printf("%lld",ans);
	return 0;
} 
posted @ 2025-09-23 14:55  qwqSW  阅读(11)  评论(0)    收藏  举报