大致题意:求所有长度为K的连续子区间的最长上升子串长度。
我们知道,朴素的LIS问题有O(nlogn)的解法,但是如果有很多个区间,显然也是做不了的。这里我们学习到了一种解决LIS问题的新姿势。
我们考虑每一个数字a[i],令nxt[i]表示它右边第一个比它大的数字的位置。这样每一个节点要么只有一个nxt[i],要么没有nxt[i]。如果我们把每一个i与nxt[i]连一条边,我们就可以构成一个森林,弄一个虚拟的总根,我们就可以构成一棵树。仔细观察这棵树,对于任意两个节点u和v,如果u是v的祖先,而且u和v同时在某个区间内,那么从u到v路径的长度构成这个区间内的一个上升子串。一个区间的LIS,就是所有上升子串中长度最长的长度。那么我们只需要维护区间内最长的从后代到祖先的长度。
我们考虑对这棵树的dfs序建立一棵线段树。如果某个节点在区间内,那么把它所有的后代都加一。如此对区间内所有的点做完之后,你会发现这可线段树里面的最大值就是LIS的长度。我们只需要不断地滑动这个区间,动态维护每个节点以及其后代的状态和最大值,就能够知道每个区间的LIS。总的时间复杂度为O(NlogN),具体见代码:
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define LL long long
#define sc(x) scanf("%d",&x)
#define scc(x,y) scanf("%d%d",&x,&y)
#define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define file(x) freopen(#x".in","r",stdin);
using namespace std;
const int N = 1e6 + 10;
struct ST
{
#define ls i<<1
#define rs i<<1|1
struct node
{
int max,lazy,l,r;
} T[N<<2];
inline void push_up(int i)
{
T[i].max=max(T[ls].max,T[rs].max);
}
void build(int i,int l,int r)
{
T[i]=node{0,0,l,r};
if (l==r)
{
T[i].max=0;
return;
}
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
push_up(i);
}
void push_down(int i)
{
T[ls].lazy+=T[i].lazy;
T[rs].lazy+=T[i].lazy;
T[ls].max+=T[i].lazy;
T[rs].max+=T[i].lazy;
T[i].lazy=0;
}
void update(int i,int l,int r,int x)
{
if ((T[i].l==l)&&(T[i].r==r))
{
T[i].lazy+=x;
T[i].max+=x;
return;
}
if (T[i].lazy!=0) push_down(i);
int mid=(T[i].l+T[i].r)>>1;
if (mid>=r) update(ls,l,r,x);
else if (mid<l) update(rs,l,r,x);
else
{
update(ls,l,mid,x);
update(rs,mid+1,r,x);
}
push_up(i);
}
int getmax(int i,int l,int r)
{
if ((T[i].l==l)&&(T[i].r==r)) return T[i].max;
if (T[i].lazy!=0) push_down(i);
int mid=(T[i].l+T[i].r)>>1;
if (mid>=r) return getmax(ls,l,r);
else if (mid<l) return getmax(rs,l,r);
else return max(getmax(ls,l,mid),getmax(rs,mid+1,r));
}
} seg;
vector<int> g[N];
int l[N],r[N],a[N],n,k,t;
stack<pair<int,int> > st;
void dfs(int x,int fa)
{
l[x]=++t;
for(int i=0;i<g[x].size();i++)
{
int y=g[x][i];
if (y==fa) continue;
dfs(y,x);
}
r[x]=t;
}
int main()
{
scc(n,k);
for(int i=1;i<=n;i++) sc(a[i]);
st.push(make_pair(INF,n+1));
for(int i=n;i;i--)
{
while(a[i]>=st.top().first) st.pop();
g[st.top().second].push_back(i);
st.push(make_pair(a[i],i));
}
dfs(n+1,0);
seg.build(1,1,n+1);
for(int i=1;i<=k;i++)
seg.update(1,l[i],r[i],1);
for(int i=k;i<=n;i++)
{
printf("%d%c",seg.getmax(1,1,n+1)," \n"[i==n]);
seg.update(1,l[i-k+1],r[i-k+1],-1);
seg.update(1,l[i+1],r[i+1],1);
}
return 0;
}