HDU-4521 小明系列问题――小明序列(线段树)
题目大意:求LIS,但是要求LIS中相邻的两个元素之间的距离要大于d。
题目分析:线段树。节点(l,r)保存信息为LIS的最后一个元素落在[l,r]之间的最大长度。从第d+2个元素开始查询更新操作,但要在更新第i-d+1个元素信息之后。
代码如下:
# include<iostream> # include<cstdio> # include<queue> # include<vector> # include<list> # include<cstring> # include<algorithm> using namespace std; const int N=100000; int dp[N+5]; int val[N+5]; int tr[N*4+5]; void build(int rt,int l,int r) { tr[rt]=0; if(l!=r){ int mid=l+(r-l)/2; build(rt<<1,l,mid); build(rt<<1|1,mid+1,r); } } void update(int rt,int l,int r,int p,int v) { if(l==r) tr[rt]=max(tr[rt],v); else{ int mid=l+(r-l)/2; if(p<=mid) update(rt<<1,l,mid,p,v); else update(rt<<1|1,mid+1,r,p,v); tr[rt]=max(tr[rt<<1],tr[rt<<1|1]); } } int query(int rt,int l,int r,int L,int R) { if(L<=l&&r<=R) return tr[rt]; int mid=l+(r-l)/2; if(R<=mid) return query(rt<<1,l,mid,L,R); if(L>mid) return query(rt<<1|1,mid+1,r,L,R); return max(query(rt<<1,l,mid,l,mid),query(rt<<1|1,mid+1,r,mid+1,R)); } int main() { int n,d; while(~scanf("%d%d",&n,&d)) { int ans=1; build(1,0,N); for(int i=0;i<n;++i){ scanf("%d",val+i); if(i>=d+1) update(1,0,N,val[i-d-1],dp[i-d-1]); if(val[i]>0) dp[i]=query(1,0,N,0,val[i]-1)+1; else dp[i]=1; ans=max(ans,dp[i]); } printf("%d\n",ans); } return 0; }