Description

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

Solution

其实题目就是想找一个最长的波浪形队列。

DP

很显然,处理一个f[i]和g[i]就好了。
a[i]>a[k]:f[i]=max(g[k]+1,f[i]);a[i]

线段树优化

因为我要找的是一个位置,而且有值域的限制,所以可以用权值线段树。
直接打一个权值线段树维护最大值就好了。

离散化

如果怕空间爆了,可以用离散化,虽然不用都可以。

Code

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
const int maxn=100007;
const int zuida=1000000;
struct node{
int fda,gda;
}t[zuida];
struct nod{
int a,b;
}b[maxn];
using namespace std;
int i,j,k,l,n,m,ans,tot;
int a[maxn],f[maxn],g[maxn];
void insert(int x,int l,int r,int y,int z,int p){
if(l==r){
if(p==1)t[x].fda=max(t[x].fda,z);
else t[x].gda=max(t[x].gda,z);
}
else{
int mid=(l+r)/2;
if(y<=mid)insert(x*2,l,mid,y,z,p);else insert(x*2+1,mid+1,r,y,z,p);
if(p==1)t[x].fda=max(t[x*2].fda,t[x*2+1].fda);
else t[x].gda=max(t[x*2].gda,t[x*2+1].gda);
}
}
int find(int x,int l,int r,int y,int z,int p){
if(y>z)return 0;
if(l==y&&r==z){
if(p==1)return t[x].fda;
else return t[x].gda;
}
else{
int mid=(l+r)/2;
if(z<=mid)return find(x*2,l,mid,y,z,p);else if (y>mid)return find(x*2+1,mid+1,r,y,z,p);
else{
return max(find(x*2,l,mid,y,mid,p),find(x*2+1,mid+1,r,mid+1,z,p));
}
}
}
bool cmp(nod x,nod y){
return x.a<y.a;
}
int main(){
scanf("%d",&n);
fo(i,1,n){
scanf("%d",&b[i].a);b[i].b=i;
}
sort(b+1,b+1+n,cmp);
a[b[1].b]=1;tot=1;
fo(i,2,n){
if(b[i-1].a==b[i].a)a[b[i].b]=tot;
else a[b[i].b]=++tot;
}
f[1]=g[1]=1;
insert(1,1,tot,a[1],f[1],1);
insert(1,1,tot,a[1],g[1],2);
fo(i,2,n){
f[i]=find(1,1,tot,1,a[i]-1,2)+1;
g[i]=find(1,1,tot,a[i]+1,tot,1)+1;
insert(1,1,tot,a[i],f[i],1);
insert(1,1,tot,a[i],g[i],2);
ans=max(ans,f[i]);
ans=max(ans,g[i]);
}
printf("%d\n",ans);
}