思路:先设线段树保存区间最大值,对于第一只企鹅,设其可生存时间为无穷大,将其权值插入线段树,对于后面的企鹅,如果权值小于左边的,那么将会被左边的企鹅用一天时间吃掉,意味着这只企鹅的可生存时间为1,有一天的时间去吃其他的企鹅,并将这只企鹅权值插入线段树,同时也也意味着左边的企鹅已生存时间+1,如果左边企鹅已生存时间等于可生存时间,从线段树中删除它,如果一只企鹅a权值大于左边,那么就从线段树找一只权值大于a的企鹅x,找到后,将x的已生存时间+1,如果x的已生存时间等于可生存时间,就抹去这只企鹅,同时将a的可生存时间设为x的已生存时间,再将a的权值插入线段树。线段树要优先从右子树查找。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e6+10;
const int inf=1e8;
int vis[maxn],a[maxn],flag[maxn],c[maxn];
int tree[maxn*3];
int n,tot;
void update(int l,int r,int o,int k,int value)
{
if(l==r)
{
tree[o]=value;
return;
}
int ls=o*2,rs=o*2+1,m=(l+r)/2;
if(k<=m)
update(l,m,ls,k,value);
else
update(m+1,r,rs,k,value);
tree[o]=max(tree[ls],tree[rs]);
}
int query(int l,int r,int o,int value)
{
if(tree[o]<=value)
return 0;
if(l==r)
return tree[o];
int ls=o*2,rs=o*2+1,m=(l+r)/2;
if(tree[rs]>value) //优先从右边查找
return query(m+1,r,rs,value);
else
return query(l,m,ls,value);
}
int main()
{
while(~scanf("%d",&n))
{
memset(vis,0,sizeof(vis));//已生存时间
tot=0;
a[0]=0;
memset(tree,0,sizeof(tree));
for(int i=1;i<maxn;i++)
flag[i]=inf; //可生存时间
int ans=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
c[a[i]]=i;
if(a[i]<a[i-1])
{
flag[a[i]]=1; //这只企鹅可生存时间为1
vis[a[i-1]]++;//左边的企鹅已生存时间+1
if(vis[a[i-1]]>=flag[a[i-1]])
update(1,n,1,i-1,0); //抹去左边的企鹅
}
else
{
int t=query(1,n,1,a[i]);
if(!t)
update(1,n,1,i,a[i]);//没有企鹅能吃它
else
{
vis[t]++; //权值为t的企鹅已生存时间+1
flag[a[i]]=vis[t]; //这只企鹅的可生存时间等于企鹅t的已生存时间
update(1,n,1,i,a[i]);//将这只企鹅插入
if(vis[t]>=flag[t])
update(1,n,1,a[t],0);
}
}
}
for(int i=1;i<=n;i++)
ans=max(ans,vis[i]);
printf("%d\n",ans);
}
}