【CF1132G】Greedy Subsequences

题目

For some array c, let’s denote a greedy subsequence as a sequence of indices p1, p2, …, pl such that 1≤p1<p2<⋯<pl≤|c|, and for each i∈[1,l−1], pi+1 is the minimum number such that pi+1>pi and c[pi+1]>c[pi].

You are given an array a1,a2,…,an. For each its subsegment of length k, calculate the length of its longest greedy subsequence.

Input
The first line contains two integers n and k (1≤k≤n≤106) — the length of array a and the length of subsegments.

The second line contains n integers a1,a2,…,an (1≤ai≤n) — array a.

Output
Print n−k+1 integers — the maximum lengths of greedy subsequences of each subsegment having length k. The first number should correspond to subsegment a[1…k], the second — to subsegment a[2…k+1], and so on.

Examples
inputCopy
6 4
1 5 2 5 3 6
outputCopy
2 2 3
inputCopy
7 6
4 5 2 5 3 6 6
outputCopy
3 3
Note
In the first example:

[1,5,2,5] — the longest greedy subsequences are 1,2 ([c1,c2]=[1,5]) or 3,4 ([c3,c4]=[2,5]).
[5,2,5,3] — the sequence is 2,3 ([c2,c3]=[2,5]).
[2,5,3,6] — the sequence is 1,2,4 ([c1,c2,c4]=[2,5,6]).
In the second example:

[4,5,2,5,3,6] — the longest greedy subsequences are 1,2,6 ([c1,c2,c6]=[4,5,6]) or 3,4,6 ([c3,c4,c6]=[2,5,6]).
[5,2,5,3,6,6] — the subsequence is 2,3,5 ([c2,c3,c5]=[2,5,6]).

题意

给定一个序列a,定义它的最长贪心严格上升子序列为b满足若ai在b中则ai之后第一个比它大的也在b中。给出一个数k,求出所有长度为k的子区间的最长贪心严格上升子序列。

思路

感谢beginend大爷的指导。

我们可以把它看成一棵树(根据next连边)。

现在要求一些关键点最多能往上跳多少步。

如果只有一个询问,那么随便做。但现在有多个询问,那么要维护一个可以插入删除的树。

不难发现,如果加入一个点,那么它的子树一定已经加入过,这只需一个区间加就行。如果删除一个数,那么它的子树早就被删了,秩序把那个点赋值为-INF即可

用线段树轻松维护

代码

#include<iostream>
#include<cstdio>
using namespace std;
#define MAX 1000100
inline int read()
{
    int x=0;bool t=false;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
int a[MAX],n,K,St[MAX],top,L[MAX];
#define lson (now<<1)
#define rson (now<<1|1)
int t[MAX<<2],tag[MAX<<2];
void puttag(int now,int w){t[now]+=w;tag[now]+=w;}
void pushdown(int now)
{
    if(!tag[now])return;
    puttag(lson,tag[now]);puttag(rson,tag[now]);
    tag[now]=0;
}
void Modify(int now,int l,int r,int L,int R,int w)
{
    if(L<=l&&r<=R){puttag(now,w);return;}
    int mid=(l+r)>>1;pushdown(now);
    if(L<=mid)Modify(lson,l,mid,L,R,w);
    if(R>mid)Modify(rson,mid+1,r,L,R,w);
    t[now]=max(t[lson],t[rson]);
}
int Query(int now,int l,int r,int L,int R)
{
    if(L<=l&&r<=R)return t[now];
    int mid=(l+r)>>1,ret=0;pushdown(now);
    if(L<=mid)ret=max(ret,Query(lson,l,mid,L,R));
    if(R>mid)ret=max(ret,Query(rson,mid+1,r,L,R));
    return ret;
}
int main()
{
    n=read();K=read();
    for(int i=1;i<=n;++i)a[i]=read();
    for(int i=1;i<=n;++i)
    {
        while(top&&a[St[top]]<a[i])--top;
        L[i]=St[top];St[++top]=i;
    }
    for(int i=1;i<=n;++i)
    {
        Modify(1,1,n,L[i]+1,i,1);
        if(i>=K)printf("%d ",Query(1,1,n,i-K+1,i));
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值