code vs 3289 花匠 (线段树优化dp)

传送门:


题目描述:花匠栋栋种了一排花,每株花都有自己的高度。花儿越长越大,也越来越挤。栋栋决定把这排中的一部分花移走,将剩下的留在原地,使得剩下的花能有空间长大,同时,栋栋希望剩下的花排列得比较别致。
具体而言,栋栋的花的高度可以看成一列整数h_1, h_2, … , h_n。设当一部分花被移走后,剩下的花的高度依次为g_1, g_2, … , g_m,则栋栋希望下面两个条件中至少有一个满足:
条件 A:对于所有的1 g_2i-1,且g_2i > g_2i+1; 
条件 B:对于所有的1
注意上面两个条件在m = 1时同时满足,当m > 1时最多有一个能满足。
请问,栋栋最多能将多少株花留在原地。


题解:线段树优化dp

题目中的条件a,b,其实都是等价的,无非都是要求数列是一上一下错排的。

f[i][0]表示选到i是上升趋势的最长序列长度。

f[i][1]表示选到i是下降趋势的最长序列长度。

h[j]

h[j]>h[i] f[i][1]=max(f[i][1],f[j][0]+1)

然后用线段树优化dp

#include
#include
#include
#include
#include
#define N 2000003
using namespace std;
int n,m;
int f[N][3],h[N],tr[N*4],tr1[N*4];
void update(int now)
{
	tr[now]=max(tr[now<<1],tr[now<<1|1]);
	tr1[now]=max(tr1[now<<1],tr1[now<<1|1]);
}
void change(int now,int l,int r,int x,int v,int v1)
{
	if (l==r) {
		tr[now]=v;
		tr1[now]=v1;
		return;
	}
	int mid=(l+r)/2;
	if (x<=mid) change(now<<1,l,mid,x,v,v1);
	else change(now<<1|1,mid+1,r,x,v,v1);
	update(now);
}
int qjmax(int now,int l,int r,int ll,int rr,int v)
{
	if (ll>rr) return 0;
	if (ll<=l&&r<=rr) if (!v) return tr[now];
	                  else return tr1[now];
	int mid=(l+r)/2;
	int ans=0;
	if (ll<=mid) ans=max(ans,qjmax(now<<1,l,mid,ll,rr,v));
	if (rr>mid) ans=max(ans,qjmax(now<<1|1,mid+1,r,ll,rr,v));
	return ans;
}
int main()
{
	scanf("%d",&n);
	int maxn=0;
	for (int i=1;i<=n;i++) scanf("%d",&h[i]),maxn=max(maxn,h[i]);
	f[1][1]=f[1][0]=1; change(1,0,maxn,h[1],f[1][0],f[1][1]);
	int ans=0;
	for (int i=2;i<=n;i++)
	 {
	 	f[i][0]=qjmax(1,0,maxn,0,h[i]-1,1)+1;
	 	f[i][1]=qjmax(1,0,maxn,h[i]+1,maxn,0)+1;
	    change(1,0,maxn,h[i],f[i][0],f[i][1]);
	    ans=max(ans,f[i][0]);
	    ans=max(ans,f[i][1]);
	 }
	cout<


你可能感兴趣的:(动态规划,线段树)